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