Example #1
0
// Returns the duration of a given kbrecording file
func getDuration(filename string) time.Duration {
	d := 0

	f, _ := os.Open(filename)
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		s := strings.SplitN(scanner.Text(), ":", 2)
		// Ignore comments in the vnc file
		if s[0] == "#" {
			continue
		}
		i, err := strconv.Atoi(s[0])
		if err != nil {
			log.Errorln(err)
			return 0
		}
		d += i
	}

	duration, err := time.ParseDuration(strconv.Itoa(d) + "ns")
	if err != nil {
		log.Errorln(err)
		return 0
	}

	return duration
}
Example #2
0
// client connection handler and transport. Messages on chan out are sent to
// the ron server. Incoming messages are put on the message queue to be routed
// by the mux. The entry to handler() also creates the tunnel transport.
func (c *Client) handler() {
	log.Debug("ron handler")

	// create a tunnel
	stop := make(chan bool)
	defer func() { stop <- true }()
	go c.handleTunnel(false, stop)

	enc := gob.NewEncoder(c.conn)
	dec := gob.NewDecoder(c.conn)

	// handle client i/o
	go func() {
		for {
			m := <-c.out
			err := enc.Encode(m)
			if err != nil {
				log.Errorln(err)
				return
			}
		}
	}()

	for {
		var m Message
		err := dec.Decode(&m)
		if err != nil {
			log.Errorln(err)
			return
		}
		c.in <- &m
	}
}
Example #3
0
func vncWsHandler(ws *websocket.Conn) {
	// URL should be of the form `/ws/<vm_name>`
	path := strings.Trim(ws.Config().Location.Path, "/")

	fields := strings.Split(path, "/")
	if len(fields) != 2 {
		return
	}
	vmName := fields[1]

	vms := GlobalVMs()
	vm, err := vms.findKvmVM(vmName)
	if err != nil {
		log.Errorln(err)
		return
	}

	// Undocumented "feature" of websocket -- need to set to PayloadType in
	// order for a direct io.Copy to work.
	ws.PayloadType = websocket.BinaryFrame

	// connect to the remote host
	rhost := fmt.Sprintf("%v:%v", vm.Host, vm.VNCPort)
	remote, err := net.Dial("tcp", rhost)
	if err != nil {
		log.Errorln(err)
		return
	}
	defer remote.Close()

	go io.Copy(ws, remote)
	io.Copy(remote, ws)

	log.Info("ws client disconnected from %v", rhost)
}
Example #4
0
// return a file to a client requesting it via the clients GetFile() call
func (s *Server) sendFile(m *Message) {
	log.Debug("ron sendFile: %v", m.Filename)

	filename := filepath.Join(s.path, m.Filename)
	info, err := os.Stat(filename)
	if err != nil {
		e := fmt.Errorf("file %v does not exist: %v", filename, err)
		m.Error = e.Error()
		log.Errorln(e)
	} else if info.IsDir() {
		e := fmt.Errorf("file %v is a directory", filename)
		m.Error = e.Error()
		log.Errorln(e)
	} else {
		// read the file
		m.File, err = ioutil.ReadFile(filename)
		if err != nil {
			e := fmt.Errorf("file %v: %v", filename, err)
			m.Error = e.Error()
			log.Errorln(e)
		}
	}

	// route this message ourselves instead of using the mux, because we
	// want the type to still be FILE
	s.clientLock.Lock()
	defer s.clientLock.Unlock()
	if c, ok := s.clients[m.UUID]; ok {
		c.out <- m
	} else {
		log.Error("no such client %v", m.UUID)
	}
}
Example #5
0
func (t *Tunnel) handleRemote(m *tunnelMessage) {
	host := m.Host
	port := m.Port
	TID := m.TID

	// attempt to connect to the host/port
	conn, err := net.Dial("tcp", fmt.Sprintf("%v:%v", host, port))
	if err == nil {
		in := t.chans.add(TID)
		go t.transfer(in, conn, TID)
		return
	}

	log.Errorln(err)

	resp := &tunnelMessage{
		Type:  CLOSED,
		TID:   TID,
		Error: err.Error(),
	}

	if err := t.sendMessage(resp); err != nil {
		log.Errorln(err)
	}
}
Example #6
0
// dirHandler serves a directory listing for the requested path, rooted at basePath.
func dirHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/favicon.ico" {
		http.Error(w, "not found", 404)
		return
	}
	const base = "."
	name := filepath.Join(base, r.URL.Path)

	if isDoc(name) {
		err := renderDoc(w, name)
		if err != nil {
			log.Errorln(err)
			http.Error(w, err.Error(), 500)
		}
		return
	}
	if isDir, err := dirList(w, name); err != nil {
		log.Errorln(err)
		http.Error(w, err.Error(), 500)
		return
	} else if isDir {
		return
	}
	http.FileServer(http.Dir(*f_root)).ServeHTTP(w, r)
}
Example #7
0
func kill(pid int) {
	Client.Lock()
	defer Client.Unlock()

	if pid == -1 {
		// Wildcard
		log.Info("killing all processes")
		for _, p := range Client.Processes {
			if err := p.process.Kill(); err != nil {
				log.Errorln(err)
			}
		}

		return
	}

	log.Info("killing PID %v", pid)
	if p, ok := Client.Processes[pid]; ok {
		if err := p.process.Kill(); err != nil {
			log.Errorln(err)
		}

		return
	}

	log.Error("no such process: %v", pid)
}
Example #8
0
func containerFifos(vmFSPath string, vmInstancePath string, vmFifos int) error {
	err := os.Mkdir(filepath.Join(vmFSPath, "/dev/fifos"), 0755)
	if err != nil {
		log.Errorln(err)
		return nil
	}
	for i := 0; i < vmFifos; i++ {
		src := filepath.Join(vmInstancePath, fmt.Sprintf("fifo%v", i))
		_, err := os.Stat(src)
		if err != nil {
			log.Errorln(err)
			return err
		}

		dst := filepath.Join(vmFSPath, fmt.Sprintf("/dev/fifos/fifo%v", i))

		// dst must exist for bind mounting to work
		f, err := os.Create(dst)
		if err != nil {
			log.Errorln(err)
			return err
		}
		f.Close()
		log.Debug("bind mounting: %v -> %v", src, dst)
		err = syscall.Mount(src, dst, "", syscall.MS_BIND, "")
		if err != nil {
			log.Errorln(err)
			return err
		}
	}
	return nil
}
Example #9
0
func (vm *KvmVM) connectVNC() error {
	l, err := net.Listen("tcp", "")
	if err != nil {
		return err
	}

	// Keep track of shim so that we can close it later
	vm.vncShim = l
	vm.VNCPort = l.Addr().(*net.TCPAddr).Port
	ns := fmt.Sprintf("%v:%v", vm.Namespace, vm.Name)

	go func() {
		defer l.Close()

		for {
			// Sit waiting for new connections
			remote, err := l.Accept()
			if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
				return
			} else if err != nil {
				log.Errorln(err)
				return
			}

			go func() {
				defer remote.Close()

				// Dial domain socket
				local, err := net.Dial("unix", vm.path("vnc"))
				if err != nil {
					log.Error("unable to dial vm vnc: %v", err)
					return
				}
				defer local.Close()

				// copy local -> remote
				go io.Copy(remote, local)

				// Reads will implicitly copy from remote -> local
				tee := io.TeeReader(remote, local)
				for {
					// Read
					msg, err := vnc.ReadClientMessage(tee)
					if err != nil {
						if err == io.EOF || strings.Contains(err.Error(), "closed network") {
							break
						}
						log.Errorln(err)
					}
					if r, ok := vncKBRecording[ns]; ok {
						r.RecordMessage(msg)
					}
				}
			}()
		}
	}()

	return nil
}
Example #10
0
// recvFiles retrieves a list of files from the ron server by requesting each
// one individually.
func recvFiles(files []*ron.File) {
	start := time.Now()
	var size int64

	for _, v := range files {
		log.Info("requesting file %v", v)

		dst := filepath.Join(*f_path, "files", v.Name)

		if _, err := os.Stat(dst); err == nil {
			// file exists (TODO: overwrite?)
			log.Info("skipping %v -- already exists")
			continue
		}

		m := &ron.Message{
			Type:     ron.MESSAGE_FILE,
			UUID:     Client.UUID,
			Filename: v.Name,
		}

		if err := sendMessage(m); err != nil {
			log.Error("send failed: %v", err)
			return
		}

		resp := <-Client.fileChan
		if resp.Filename != v.Name {
			log.Error("filename mismatch: %v != %v", resp.Filename, v.Name)
			continue
		}

		if resp.Error != "" {
			log.Error("%v", resp.Error)
			continue
		}

		dir := filepath.Dir(dst)

		if err := os.MkdirAll(dir, os.FileMode(0770)); err != nil {
			log.Errorln(err)
			continue
		}

		if err := ioutil.WriteFile(dst, resp.File, v.Perm); err != nil {
			log.Errorln(err)
			continue
		}

		size += int64(len(resp.File))
	}

	d := time.Since(start)
	rate := (float64(size) / 1024 / d.Seconds())

	log.Debug("received %v bytes in %v (%v KBps)", size, d, rate)

	return
}
Example #11
0
func runCommand(command []string, background bool) (string, string) {
	var stdout bytes.Buffer
	var stderr bytes.Buffer

	path, err := exec.LookPath(command[0])
	if err != nil {
		log.Errorln(err)
		return "", err.Error()
	}

	cmd := &exec.Cmd{
		Path:   path,
		Args:   command,
		Stdout: &stdout,
		Stderr: &stderr,
	}
	log.Info("executing: %v", command)

	if background {
		log.Debug("starting in background")
		if err := cmd.Start(); err != nil {
			log.Errorln(err)
			return "", stderr.String()
		}

		pid := cmd.Process.Pid

		Client.Lock()
		defer Client.Unlock()
		Client.Processes[pid] = &Process{
			PID:     pid,
			Command: command,
			process: cmd.Process,
		}

		go func() {
			cmd.Wait()
			log.Info("command exited: %v", command)
			if stdout.Len() > 0 {
				log.Info(stdout.String())
			}
			if stderr.Len() > 0 {
				log.Info(stderr.String())
			}

			Client.Lock()
			defer Client.Unlock()
			delete(Client.Processes, pid)
		}()

		return "", ""
	}

	if err := cmd.Run(); err != nil {
		log.Errorln(err)
	}
	return stdout.String(), stderr.String()
}
Example #12
0
func sshHandleChannel(conn net.Conn, newChannel ssh.NewChannel) {
	// Channels have a type, depending on the application level protocol
	// intended. In the case of a shell, the type is "session" and ServerShell
	// may be used to present a simple terminal interface.
	if newChannel.ChannelType() != "session" {
		newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
		return
	}
	channel, requests, err := newChannel.Accept()
	if err != nil {
		log.Errorln(err)
		return
	}

	// Sessions have out-of-band requests such as "shell", "pty-req" and "env".
	// Here we handle only the "shell" request.
	go func(in <-chan *ssh.Request) {
		for req := range in {
			ok := false
			switch req.Type {
			case "shell":
				ok = true
				if len(req.Payload) > 0 {
					// We don't accept any commands, only the default shell.
					ok = false
				}
			case "pty-req":
				ok = true
			}
			req.Reply(ok, nil)
		}
	}(requests)

	term := terminal.NewTerminal(channel, "> ")

	go func() {
		defer channel.Close()

		for {
			line, err := term.ReadLine()
			start := time.Now().UnixNano()
			if err != nil {
				if err != io.EOF {
					log.Errorln(err)
				}
				return
			}
			sshReportChan <- uint64(len(line))
			// just echo the message
			log.Debugln("ssh received: ", line)
			term.Write([]byte(line))
			term.Write([]byte{'\r', '\n'})

			stop := time.Now().UnixNano()
			log.Info("ssh %v %vns", conn.RemoteAddr(), uint64(stop-start))
		}
	}()
}
Example #13
0
func (t *Tunnel) handle(in chan *tunnelMessage, conn net.Conn, TID int32) {
	// begin forwarding until an error occurs
	go func() {
		for {
			select {
			case <-t.quit:
				conn.Close()
				return
			case m := <-in:
				if m.Type == CLOSED {
					if m.Error != "" {
						log.Errorln(m.Error)
						conn.Close()
						break
					}
				}
				_, err := conn.Write(m.Data)
				if err != nil {
					log.Errorln(err)
					conn.Close()
					t.out <- &tunnelMessage{
						Type:  CLOSED,
						TID:   TID,
						Error: err.Error(),
					}
					break
				}
			}
		}
	}()

	for {
		var buf = make([]byte, BUFFER_SIZE)
		n, err := conn.Read(buf)
		if err != nil {
			conn.Close()
			closeMessage := &tunnelMessage{
				Type: CLOSED,
				TID:  TID,
			}
			if err != io.EOF && !strings.Contains(err.Error(), errClosing) {
				log.Errorln(err)
				closeMessage.Error = err.Error()
			}
			t.out <- closeMessage
			t.unregisterTID(TID)
			break
		}
		m := &tunnelMessage{
			Type: DATA,
			TID:  TID,
			Data: buf[:n],
		}
		t.out <- m
	}
}
Example #14
0
// aggressively cleanup container cruff, called by the nuke api
func containerNuke() {
	// walk minimega cgroups for tasks, killing each one
	cgroupFreezer := filepath.Join(*f_cgroup, "freezer", "minimega")
	cgroupMemory := filepath.Join(*f_cgroup, "memory", "minimega")
	cgroupDevices := filepath.Join(*f_cgroup, "devices", "minimega")
	cgroups := []string{cgroupFreezer, cgroupMemory, cgroupDevices}

	for _, cgroup := range cgroups {
		if _, err := os.Stat(cgroup); err == nil {
			err := filepath.Walk(cgroup, containerNukeWalker)
			if err != nil {
				log.Errorln(err)
			}
		}
	}

	// Allow udev to sync
	time.Sleep(time.Second * 1)

	// umount megamount_*, this include overlayfs mounts
	d, err := ioutil.ReadFile("/proc/mounts")
	if err != nil {
		log.Errorln(err)
	} else {
		mounts := strings.Split(string(d), "\n")
		for _, m := range mounts {
			if strings.Contains(m, "megamount") {
				mount := strings.Split(m, " ")[1]
				if err := syscall.Unmount(mount, 0); err != nil {
					log.Error("overlay unmount %s: %v", m, err)
				}
			}
		}
	}

	containerCleanCgroupDirs()

	// remove meganet_* from /var/run/netns
	if _, err := os.Stat("/var/run/netns"); err == nil {
		netns, err := ioutil.ReadDir("/var/run/netns")
		if err != nil {
			log.Errorln(err)
		} else {
			for _, n := range netns {
				if strings.Contains(n.Name(), "meganet") {
					err := os.Remove(filepath.Join("/var/run/netns", n.Name()))
					if err != nil {
						log.Errorln(err)
					}
				}
			}
		}
	}
}
Example #15
0
func containerTeardown() {
	if cgroupInitialized {
		err := os.Remove(CGROUP_PATH)
		if err != nil {
			log.Errorln(err)
		}
		err = syscall.Unmount(CGROUP_ROOT, 0)
		if err != nil {
			log.Errorln(err)
		}
	}
}
Example #16
0
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)
		}
	}
}
Example #17
0
// runCommand runs a command through a JSON pipe.
func runCommand(cmd Command) chan *localResponse {
	conn, err := net.Dial("unix", path.Join(*f_minimega, "minimega"))
	if err != nil {
		log.Errorln(err)
		return nil
	}

	enc := json.NewEncoder(conn)
	dec := json.NewDecoder(conn)

	log.Debug("encoding command: %v", cmd)

	err = enc.Encode(cmd)
	if err != nil {
		log.Errorln("local command json encode: %v", err)
		return nil
	}

	log.Debugln("encoded command:", cmd)

	respChan := make(chan *localResponse)

	go func() {
		defer close(respChan)

		for {
			var r localResponse
			err = dec.Decode(&r)
			if err != nil {
				if err == io.EOF {
					log.Infoln("server disconnected")
					return
				}

				log.Errorln("local command json decode: %v", err)
				return
			}

			respChan <- &r
			if !r.More {
				log.Debugln("got last message")
				break
			} else {
				log.Debugln("expecting more data")
			}
		}
	}()

	return respChan
}
Example #18
0
func (a SortEth) Less(i, j int) bool {
	// sort on the integer part of an interface name, which we assume will
	// be in the form of string+int
	idxI, err := strconv.Atoi(strings.TrimLeft(a[i], trim))
	if err != nil {
		log.Errorln(err)
		return false
	}
	idxJ, err := strconv.Atoi(strings.TrimLeft(a[j], trim))
	if err != nil {
		log.Errorln(err)
		return false
	}
	return idxI < idxJ
}
Example #19
0
// a filename completer for goreadline that searches for the file: prefix,
// attempts to find matching files, and returns an array of candidates.
func iomCompleter(line string) []string {
	f := strings.Fields(line)
	if len(f) == 0 {
		return nil
	}
	last := f[len(f)-1]
	if strings.HasPrefix(last, IOM_HELPER_MATCH) {
		fileprefix := strings.TrimPrefix(last, IOM_HELPER_MATCH)
		matches := iom.Info(fileprefix + "*")
		log.Debug("got raw matches: %v", matches)

		// we need to clean up matches to collapse directories, unless
		// there is a directory common prefix, in which case we
		// collapse offset by the number of common directories.
		dlcp := lcp(matches)
		didx := strings.LastIndex(dlcp, string(filepath.Separator))
		drel := ""
		if didx > 0 {
			drel = dlcp[:didx]
		}
		log.Debug("dlcp: %v, drel: %v", dlcp, drel)

		if len(fileprefix) < len(drel) {
			r := IOM_HELPER_MATCH + drel + string(filepath.Separator)
			return []string{r, r + "0"} // hack to prevent readline from fastforwarding beyond the directory name
		}

		var finalMatches []string
		for _, v := range matches {
			if strings.Contains(v, "*") {
				continue
			}
			r, err := filepath.Rel(drel, v)
			if err != nil {
				log.Errorln(err)
				return nil
			}
			dir := filepath.Dir(r)
			if dir == "." {
				finalMatches = append(finalMatches, IOM_HELPER_MATCH+v)
				continue
			}

			paths := strings.Split(dir, string(filepath.Separator))
			found := false
			for _, d := range finalMatches {
				if d == paths[0]+string(filepath.Separator) {
					found = true
					break
				}
			}
			if !found {
				finalMatches = append(finalMatches, IOM_HELPER_MATCH+filepath.Join(drel, paths[0])+string(filepath.Separator))
			}
		}

		return finalMatches
	}
	return nil
}
Example #20
0
func teardown() {
	// Clear namespace so that we hit all the VMs
	SetNamespace("")

	vncClear()
	clearAllCaptures()
	vms.Kill(Wildcard)
	dnsmasqKillAll()
	ksmDisable()
	vms.Flush()
	vms.CleanDirs()
	containerTeardown()

	if err := bridgesDestroy(); err != nil {
		log.Errorln(err)
	}

	commandSocketRemove()
	goreadline.Rlcleanup()

	if err := os.Remove(filepath.Join(*f_base, "minimega.pid")); err != nil {
		log.Fatalln(err)
	}

	if cpuProfileOut != nil {
		pprof.StopCPUProfile()
		cpuProfileOut.Close()
	}

	os.Exit(0)
}
Example #21
0
// readFile reads the file by name and returns a message that can be sent back
// to the client.
func (s *Server) readFile(f string) *Message {
	log.Debug("readFile: %v", f)

	filename := filepath.Join(s.path, f)
	m := &Message{
		Type:     MESSAGE_FILE,
		Filename: f,
	}

	info, err := os.Stat(filename)
	if err != nil {
		m.Error = fmt.Sprintf("file %v does not exist: %v", filename, err)
	} else if info.IsDir() {
		m.Error = fmt.Sprintf("file %v is a directory", filename)
	} else {
		// read the file
		m.File, err = ioutil.ReadFile(filename)
		if err != nil {
			m.Error = fmt.Sprintf("file %v: %v", filename, err)
		}
	}

	if m.Error != "" {
		log.Errorln(m.Error)
	}

	return m
}
Example #22
0
// Starts a Ron server on the specified port
func (s *Server) Listen(port int) error {
	ln, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
	if err != nil {
		return err
	}

	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				log.Errorln(err)
				return
			}

			log.Debug("new connection from: %v", conn.RemoteAddr())

			go func() {
				addr := conn.RemoteAddr()
				s.clientHandler(conn)
				log.Debug("disconnected from: %v", addr)
			}()
		}
	}()

	return nil
}
Example #23
0
// return names of bridges as shown in f_base/bridges. Optionally include
// bridges that existed before minimega was launched
func nukeBridgeNames(preExist bool) []string {
	var ret []string

	b, err := os.Open(filepath.Join(*f_base, "bridges"))
	if os.IsNotExist(err) {
		return nil
	} else if err != nil {
		log.Errorln(err)
		return nil
	}

	scanner := bufio.NewScanner(b)
	// skip the first line
	scanner.Scan()
	for scanner.Scan() {
		f := strings.Fields(scanner.Text())
		log.Debugln(f)
		if len(f) <= 2 {
			continue
		}
		if (f[1] == "true" && preExist) || f[1] == "false" {
			ret = append(ret, f[0])
		}
	}
	log.Debug("nukeBridgeNames got: %v", ret)
	return ret
}
Example #24
0
func commandSocketRemove() {
	f := filepath.Join(*f_base, "minimega")
	err := os.Remove(f)
	if err != nil {
		log.Errorln(err)
	}
}
Example #25
0
File: vm.go Project: npe9/minimega
// Get the VM info from all hosts optionally applying column/row filters.
// Returns a map with keys for the hostnames and values as the tabular data
// from the host.
func globalVmInfo() map[string]VMs {
	cmdStr := "vm info"

	res := map[string]VMs{}

	cmd := minicli.MustCompile(cmdStr)
	cmd.Record = false

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

			switch data := resp.Data.(type) {
			case VMs:
				res[resp.Host] = data
			default:
				log.Error("unknown data field in vm info")
			}
		}
	}

	return res
}
Example #26
0
func commandSocketRemove() {
	f := *f_base + "minimega"
	err := os.Remove(f)
	if err != nil {
		log.Errorln(err)
	}
}
Example #27
0
func sendCommand(s string) string {
	if strings.TrimSpace(s) == "" {
		return ""
	}

	log.Debug("sendCommand: %v", s)

	mm, err := dial(*f_minimega)
	if err != nil {
		log.Errorln(err)
		return err.Error()
	}
	defer mm.Close()

	cmd := &minicli.Command{Original: s}

	var responses string
	for resp := range mm.Run(cmd) {
		if r := resp.Rendered; r != "" {
			responses += r + "\n"
		}
		if e := resp.Resp.Error(); e != "" {
			responses += e + "\n"
		}
	}
	return responses
}
Example #28
0
func webHosts(w http.ResponseWriter, r *http.Request) {
	table := htmlTable{
		Header:  []string{},
		Tabular: [][]interface{}{},
		ID:      "example",
		Class:   "hover",
	}

	cmd := minicli.MustCompile("host")
	cmd.Record = false

	for resps := range runCommandGlobally(cmd) {
		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)
}
Example #29
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)
			}
		}()
	}
}
Example #30
0
// Handle incoming "get file info" messages by looking up if we have the file
// and responding with the number of parts or a NACK.  Also process directories
// and globs, populating the Glob field of the IOMMessage if needed.
func (iom *IOMeshage) handleInfo(m *IOMMessage) {
	// do we have this file, rooted at iom.base?
	resp := IOMMessage{
		From:     iom.node.Name(),
		Type:     TYPE_RESPONSE,
		Filename: m.Filename,
		TID:      m.TID,
	}

	glob, parts, err := iom.fileInfo(filepath.Join(iom.base, m.Filename))
	if err != nil {
		resp.ACK = false
	} else if len(glob) == 1 && glob[0] == m.Filename {
		resp.ACK = true
		resp.Part = parts
		fi, err := os.Stat(filepath.Join(iom.base, m.Filename))
		if err != nil {
			resp.ACK = false
		} else {
			resp.Perm = fi.Mode() & os.ModePerm
		}
		if log.WillLog(log.DEBUG) {
			log.Debugln("handleInfo found file with parts: ", resp.Part)
		}
	} else {
		// populate Glob
		resp.ACK = true
		resp.Glob = glob
	}

	_, err = iom.node.Set([]string{m.From}, resp)
	if err != nil {
		log.Errorln("handleInfo: sending message: ", err)
	}
}