Example #1
0
/*
 *  Invoke the tegu_add_mirror or tegu_del_mirror command on a remote host in order to add/remove a mirror.
 */
func do_mirrorwiz(req json_action, broker *ssh_broker.Broker, path *string) {
	startt := time.Now().UnixNano()

	cstr := ""
	switch req.Qdata[0] {
	case "add":
		cstr = fmt.Sprintf(`PATH=%s:$PATH tegu_add_mirror %s %s %s`, *path, req.Qdata[1], req.Qdata[2], req.Qdata[3])
		if len(req.Qdata) > 4 {
			// If VLAN list is in the arguments, tack that on the end
			cstr += " " + req.Qdata[4]
		}

	case "del":
		cstr = fmt.Sprintf(`PATH=%s:$PATH tegu_del_mirror %s`, *path, req.Qdata[1])
	}
	if cstr != "" {
		sheep.Baa(1, "via broker on %s: %s", req.Hosts[0], cstr)
		_, stderr, err := broker.Run_cmd(req.Hosts[0], cstr)
		if err != nil {
			sheep.Baa(0, "ERR: send mirror cmd failed host=%s: %s	[TGUAGN005]", req.Hosts[0], err)
		} else {
			sheep.Baa(2, "mirror cmd succesfully sent: %s", cstr)
		}
		if sheep.Would_baa(2) || err != nil {
			dump_stderr(*stderr, "addmirror"+req.Hosts[0]) // always dump on error, or if chatty
		}
	} else {
		sheep.Baa(0, "Unrecognized mirror command: "+req.Qdata[0])
	}
	endt := time.Now().UnixNano()
	sheep.Baa(1, "do_mirrorwiz: %d ms elapsed", (endt-startt)/1000)
}
Example #2
0
/*
	Extracts the information from the action passed in and causes the fmod command
	to be executed.
*/
func do_fmod(req json_action, broker *ssh_broker.Broker, path *string, timeout time.Duration) (err error) {

	startt := time.Now().Unix()

	errcount := 0
	for f := range req.Fdata {
		cstr := fmt.Sprintf(`PATH=%s:$PATH send_ovs_fmod %s`, *path, req.Fdata[f])

		ssh_rch := make(chan *ssh_broker.Broker_msg, 256) // channel for ssh results
		// do NOT close the channel here; only senders should close

		wait4 := 0 // number of responses to wait for
		for i := range req.Hosts {
			sheep.Baa(1, "via broker on %s send fmod: %s", req.Hosts[i], cstr)

			err := broker.NBRun_cmd(req.Hosts[i], cstr, wait4, ssh_rch) // sends the file as input to be executed on the host
			if err != nil {
				msg_007(req.Hosts[i], cstr, err)
			} else {
				wait4++
			}
		}

		timer_pop := false
		errcount := 0
		for wait4 > 0 && !timer_pop { // collect responses logging any errors
			select {
			case <-time.After(timeout * time.Second): // timeout
				msg_008(wait4)
				timer_pop = true

			case resp := <-ssh_rch: // response back from the broker
				wait4--
				_, stderr, elapsed, err := resp.Get_results()
				host, _, _ := resp.Get_info()
				sheep.Baa(1, "send-fmod: received response from %s elap=%d err=%v, waiting for %d more", host, elapsed, err != nil, wait4)
				if err != nil {
					sheep.Baa(0, "ERR: unable to execute send-fmod command on %s: data=%s  %s	[TGUAGN004]", host, cstr, err)
					errcount++
				} else {
					sheep.Baa(1, "flow mod set on: %s", host)
				}
				if err != nil || sheep.Would_baa(2) {
					dump_stderr(stderr, "send-fmod"+host) // always dump on error, or if chatty
				}
			}
		}
	}

	endt := time.Now().Unix()
	sheep.Baa(1, "fmod: %ds elapsed %d fmods %d errors", endt-startt, len(req.Fdata), errcount)

	return
}
Example #3
0
/*
	Executes the setup_ovs_intermed script on each host listed. This command can take
	a significant amount of time on each host (10s of seconds) and so we submit the
	command to the broker for each host in non-blocking mode to allow them to
	run concurrently. Once submitted, we collect the results (reporting errors)
	as the broker writes the response back on the channel.
*/
func do_intermedq(req json_action, broker *ssh_broker.Broker, path *string, timeout time.Duration) {

	startt := time.Now().Unix()

	running_sim = true // prevent queuing another of these
	sheep.Baa(1, "running intermediate switch queue/fmod setup on all hosts (broker)")

	ssh_rch := make(chan *ssh_broker.Broker_msg, 256) // channel for ssh results
	// do NOT close the channel here; only senders should close

	wait4 := 0 // number of responses to wait for
	for i := range req.Hosts {
		cmd_str := fmt.Sprintf(`PATH=%s:$PATH setup_ovs_intermed -d "%s"`, *path, req.Dscps)
		sheep.Baa(1, "via broker on %s: %s", req.Hosts[i], cmd_str)

		err := broker.NBRun_cmd(req.Hosts[i], cmd_str, wait4, ssh_rch)
		if err != nil {
			msg_007(req.Hosts[i], cmd_str, err)
		} else {
			wait4++
		}
	}

	timer_pop := false
	errcount := 0
	for wait4 > 0 && !timer_pop { // collect responses logging any errors
		select {
		case <-time.After(timeout * time.Second): // timeout
			msg_008(wait4)
			timer_pop = true

		case resp := <-ssh_rch: // response back from the broker
			wait4--
			_, stderr, elapsed, err := resp.Get_results()
			host, _, _ := resp.Get_info()
			sheep.Baa(2, "setup-intermed: received response from %s elap=%d err=%v, waiting for %d more", host, elapsed, err != nil, wait4)
			if err != nil {
				msg_009("setup_intermed", host)
				errcount++
			}
			if err != nil || sheep.Would_baa(2) {
				dump_stderr(stderr, "setup-intermed"+host) // always dump on error, or if chatty
			}
		}
	}

	endt := time.Now().Unix()
	sheep.Baa(1, "setup-intermed: timeout=%v %ds elapsed for %d hosts %d errors", timer_pop, endt-startt, len(req.Hosts), errcount)
	running_sim = false
}
Example #4
0
/*
	run a command --  run as a go routine to run multiple in parallel
*/
func test_cmd(broker *ssh_broker.Broker, ch chan int, host *string, cmd *string) {

	fmt.Fprintf(os.Stderr, "test_cmd: running command %s\n", *cmd)
	stdout, stderr, err := broker.Run_cmd(*host, *cmd)
	if err != nil {
		fmt.Fprintf(os.Stderr, "command failed: %s:  %s \n", *host, err)
		fmt.Fprintf(os.Stderr, "%s", stderr.String())
	} else {
		fmt.Fprintf(os.Stderr, "command was successful:\n")
		fmt.Printf("%s\n", stdout.String())
	}

	fmt.Fprintf(os.Stderr, "go routine done: %s \n", *cmd)
	ch <- 1

	return
}
Example #5
0
/*
	run a local script --  run as a go routine to run multiple in parallel
*/
func test_script(broker *ssh_broker.Broker, ch chan int, host *string, script *string, parms *string, env_file *string) {

	fmt.Fprintf(os.Stderr, "running commnand=%s parms=%s\n", *script, *parms)
	stdout, stderr, err := broker.Run_on_host(*host, *script, *parms, *env_file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "command failed: %s:  %s \n", *host, err)
		fmt.Fprintf(os.Stderr, "%s", stderr.String())
	} else {
		fmt.Fprintf(os.Stderr, "command was successful:\n")
		fmt.Printf("%s\n", stdout.String())
	}

	fmt.Fprintf(os.Stderr, "go routine done:%s \n", *parms)
	ch <- 1

	return
}
Example #6
0
/*
	Execute a create_ovs_queues for each host in the list. The create queues script is unique inasmuch
	as it expects an input file that is supplied either as a filename as $1, or on stdin if $1 is omitted.
	To send the data file for the command to execute, we'll create a tmp file on the local machine which
	is a script that echos the data into the script:
		cat <<endKat | create_ovs_queues
			data passed to us
		endKat

	We'll use the brokers 'send script for execution' feature rather to execute our script.
*/
func do_setqueues(req json_action, broker *ssh_broker.Broker, path *string, timeout time.Duration) {
	var (
		err error
	)

	startt := time.Now().Unix()

	fname := fmt.Sprintf("/tmp/tegu_setq_%d_%x_%02d.data", os.Getpid(), time.Now().Unix(), rand.Intn(10))
	sheep.Baa(3, "adjusting queues: creating %s will contain %d items", fname, len(req.Qdata))

	f, err := os.Create(fname)
	if err != nil {
		sheep.Baa(0, "ERR: unable to create data file: %s: %s	[TGUAGN002]", fname, err)
		return
	}

	fmt.Fprintf(f, "#!/usr/bin/env ksh\ncat <<endKat | PATH=%s:$PATH create_ovs_queues\n", *path)
	for i := range req.Qdata {
		sheep.Baa(3, "writing queue info: %s", req.Qdata[i])
		fmt.Fprintf(f, "%s\n", req.Qdata[i])
	}
	fmt.Fprintf(f, "endKat\n")

	err = f.Close()
	if err != nil {
		sheep.Baa(0, "ERR: unable to create data file (close): %s: %s	[TGUAGN003]", fname, err)
		return
	}

	ssh_rch := make(chan *ssh_broker.Broker_msg, 256) // channel for ssh results
	// do NOT close the channel here; only senders should close

	wait4 := 0 // number of responses to wait for
	for i := range req.Hosts {
		sheep.Baa(1, "via broker on %s: create_ovs_queues embedded in %s", req.Hosts[i], fname)

		err := broker.NBRun_on_host(req.Hosts[i], fname, "", wait4, ssh_rch) // sends the file as input to be executed on the host
		if err != nil {
			msg_007(req.Hosts[i], "create_ovs_queues", err)
		} else {
			wait4++
		}
	}

	timer_pop := false
	errcount := 0
	for wait4 > 0 && !timer_pop { // collect responses logging any errors
		select {
		case <-time.After(timeout * time.Second): // timeout
			msg_008(wait4)
			timer_pop = true

		case resp := <-ssh_rch: // response back from the broker
			wait4--
			_, stderr, elapsed, err := resp.Get_results()
			host, _, _ := resp.Get_info()
			sheep.Baa(2, "create-q: received response from %s elap=%d err=%v, waiting for %d more", host, elapsed, err != nil, wait4)
			if err != nil {
				sheep.Baa(0, "ERR: unable to execute set queue command on %s: data=%s: %s  [TGUAGN004]", host, fname, err)
				errcount++
			} else {
				sheep.Baa(1, "queues adjusted succesfully on: %s", host)
			}
			if err != nil || sheep.Would_baa(2) {
				dump_stderr(stderr, "create-q"+host) // always dump on error, or if chatty
			}
		}
	}

	endt := time.Now().Unix()
	sheep.Baa(1, "create-q: timeout=%v %ds elapsed %d hosts %d errors", timer_pop, endt-startt, len(req.Hosts), errcount)

	if errcount == 0 { // ditch the script we built earlier if all successful
		os.Remove(fname)
	} else {
		sheep.Baa(1, "create-q: %d errors, generated script file kept: %s", fname)
	}

}
Example #7
0
/*
	Generate a map that lists physical host and mac addresses. Timeout is the max number of
	seconds that we will wait for all responses.  If timeout seconds passes before all
	responses are received we will return what we have. The map command is executed on all
	hosts, so we send a non-blocking command to the broker for each host and wait for the
	responses to come back on the channel.  This allows them to run in parallel across
	the cluster.
*/
func do_map_mac2phost(req json_action, broker *ssh_broker.Broker, path *string, timeout time.Duration) (jout []byte, err error) {
	var (
		cmd_str string
	)

	startt := time.Now().Unix()

	ssh_rch := make(chan *ssh_broker.Broker_msg, 256) // channel for ssh results
	// do NOT close this channel, only senders should close

	wait4 := 0                    // number of responses to wait for
	for k, v := range req.Hosts { // submit them all out non-blocking
		cmd_str = fmt.Sprintf("PATH=%s:$PATH map_mac2phost -p %s localhost", *path, v)
		err := broker.NBRun_cmd(req.Hosts[k], cmd_str, wait4, ssh_rch)
		if err != nil {
			msg_007(req.Hosts[k], cmd_str, err)
		} else {
			wait4++
		}
	}

	msg := agent_msg{} // message to return
	msg.Ctype = "response"
	msg.Rtype = "map_mac2phost"
	msg.Vinfo = version
	msg.State = 0

	rdata := make([]string, 8192) // might need to revisit this limit
	ridx := 0

	sheep.Baa(2, "map_mac2phost: waiting for %d responses", wait4)
	timer_pop := false // indicates a timeout for loop exit
	errcount := 0
	for wait4 > 0 && !timer_pop { // wait for responses back on the channel or the timer to pop
		select {
		case <-time.After(timeout * time.Second): // timeout after 15 seconds
			msg_008(wait4)
			timer_pop = true

		case resp := <-ssh_rch: // response from broker
			wait4--
			stdout, stderr, elapsed, err := resp.Get_results()
			host, _, _ := resp.Get_info()
			sheep.Baa(2, "map_mac2phost: received response from %s elap=%d err=%v, waiting for %d more", host, elapsed, err != nil, wait4)
			if err != nil {
				msg_009("map_mac2phost", host)
				errcount++
			} else {
				ridx = buf_into_array(stdout, rdata, ridx) // capture what came back for return
			}
			if err != nil || sheep.Would_baa(2) {
				dump_stderr(stderr, "map_mac2phost"+host) // always dump stderr on error, or in chatty mode
			}
		}
	}

	msg.Rdata = rdata[0:ridx] // return just what was filled in
	endt := time.Now().Unix()
	sheep.Baa(1, "map-mac2phost: timeout=%v %ds elapsed for %d hosts %d errors %d elements", timer_pop, endt-startt, len(req.Hosts), errcount, len(msg.Rdata))

	jout, err = json.Marshal(msg)
	return
}
Example #8
0
/*
	Oneway bandwidth flow-mod generation rolls the creation of a set of flow-mods into a single script which
	eliminates the need for Tegu to understand/know things like command line parms, bridge names and
	such.  Parms in the map are converted to script command line options.
*/
func (act *json_action) do_bwow_fmod(cmd_type string, broker *ssh_broker.Broker, path *string, timeout time.Duration) (jout []byte, err error) {
	var (
		cmd_str string
	)

	pstr := ""
	if path != nil {
		pstr = fmt.Sprintf("PATH=%s:$PATH ", *path) // path to add if needed
	}

	parms := act.Data
	cmd_str = fmt.Sprintf(`%sql_bwow_fmods `, pstr) +
		build_opt(parms["smac"], "-s") +
		build_opt(parms["dmac"], "-d") +
		build_opt(parms["extip"], "-E") +
		build_opt(parms["sproto"], "-p") +
		build_opt(parms["dproto"], "-P") +
		build_opt(parms["queue"], "-q") +
		build_opt(parms["timeout"], "-t") +
		build_opt(parms["dscp"], "-T") +
		build_opt(parms["vlan_match"], "-V") +
		build_opt(parms["ipv6"], "-6")

	sheep.Baa(1, "via broker on %s: %s", act.Hosts[0], cmd_str)

	msg := agent_msg{} // build response to send back
	msg.Ctype = "response"
	msg.Rtype = cmd_type
	msg.Rid = act.Aid // response id so tegu can map back to requestor
	msg.Vinfo = version
	msg.State = 0 // assume success

	ssh_rch := make(chan *ssh_broker.Broker_msg, 256) // channel for ssh results
	// do NOT close the channel here; only senders should close
	err = broker.NBRun_cmd(act.Hosts[0], cmd_str, 0, ssh_rch) // oneway fmods are only ever applied to one host so [0] is ok
	if err != nil {
		sheep.Baa(1, "WRN: error submitting bwow command  to %s: %s", act.Hosts[0], err)
		jout, _ = json.Marshal(msg)
		return
	}

	// TODO: this can be moved to a function
	rdata := make([]string, 8192) // response output converted to strings
	edata := make([]string, 8192)
	ridx := 0 // index of next insert point into rdata
	wait4 := 1
	timer_pop := false
	for wait4 > 0 && !timer_pop { // wait for response back on the channel or the timer to pop
		select {
		case <-time.After(timeout * time.Second): // timeout if we don't get something back soonish
			sheep.Baa(1, "WRN: timeout waiting for response from %s; cmd: %s", act.Hosts[0], cmd_str)
			timer_pop = true

		case resp := <-ssh_rch: // response from broker
			wait4--
			stdout, stderr, _, err := resp.Get_results()
			host, _, _ := resp.Get_info()
			eidx := buf_into_array(stderr, edata, 0) // capture error messages, if any
			msg.Edata = edata[0:eidx]
			if err != nil {
				msg.State = 1
				sheep.Baa(1, "WRN: error running command: host=%s: %s", host, err)
			} else {
				ridx = buf_into_array(stdout, rdata, ridx) // capture what came back for return
			}
			if err != nil || sheep.Would_baa(2) {
				dump_stderr(stderr, "bw_fmod "+host) // always dump stderr on error, or in chatty mode
			}
		}
	}

	msg.Rdata = rdata[0:ridx] // return just what was filled in

	if msg.State > 0 {
		sheep.Baa(1, "bwow_fmod (%s) failed: stdout: %d lines;  stderr: %d lines", cmd_type, len(msg.Rdata), len(msg.Edata))
		sheep.Baa(0, "ERR: %s unable to execute: %s	[TGUAGN000]", cmd_type, cmd_str)
	} else {
		sheep.Baa(1, "bwow_fmod cmd (%s) completed: stdout: %d lines;  stderr: %d lines", cmd_type, len(msg.Rdata), len(msg.Edata))
	}

	jout, err = json.Marshal(msg)
	return
}