// --- tests -------------------------------------------------------------------------- func TestPass_pledge(t *testing.T) { fmt.Fprintf(os.Stderr, "\n------- make passthrou pledge -----------\n") host := "host" port := "7890" commence := time.Now().Unix() + 3600 expiry := int64(commence + 45) id := "res-test-pass-pledge" ukey := "my-cookie" ppt1, err := gizmos.Mk_pass_pledge(&host, &port, commence, expiry, &id, &ukey) if err != nil { fmt.Fprintf(os.Stderr, "cannot make pass pledge; all other passthrough tests aborted: %s [FAIL]\n", err) t.Fail() return } fmt.Fprintf(os.Stderr, "mk successful\n") pptc := ppt1.Clone("cloned") if pptc == nil { fmt.Fprintf(os.Stderr, "cannot clone pass pledge; all other passthrough tests aborted [FAIL]\n") t.Fail() return } fmt.Fprintf(os.Stderr, "clone successful\n") host2 := "host2" port2 := "7890" id2 := "res-test-pass-pledge2" ukey2 := "my-cookie" ppt2, err := gizmos.Mk_pass_pledge(&host2, &port2, commence, expiry, &id2, &ukey2) if err != nil { fmt.Fprintf(os.Stderr, "cannot make second pass pledge; all other passthrough tests aborted: %s [FAIL]\n", err) t.Fail() return } gp := gizmos.Pledge(pptc) // must convert to a generic pledge so we can take address off next if ppt1.Equals(&gp) { fmt.Fprintf(os.Stderr, "clone reports equal [OK]\n") } else { fmt.Fprintf(os.Stderr, "clone reports !equal [FAIL]\n") } gp = gizmos.Pledge(ppt2) // must convert to a generic pledge so we can take address off next if ppt1.Equals(&gp) { fmt.Fprintf(os.Stderr, "second pledge reports equal [FAIL]\n") } else { fmt.Fprintf(os.Stderr, "second pledge reports !equal [OK]\n") } fmt.Fprintf(os.Stderr, "json: %s\n", ppt1.To_json()) fmt.Fprintf(os.Stderr, "string: %s\n", ppt1) fmt.Fprintf(os.Stderr, "chkpt: %s\n", ppt1.To_chkpt()) }
/* Pulls the reservation from the inventory. Similar to delete, but not quite the same. This will clone the pledge. The clone is expired and left in the inventory to force a reset of flowmods. The network manager is sent a request to delete the queues associated with the path and the path is removed from the original pledge. The original pledge is returned so that it can be used to generate a new set of paths based on the hosts, expiry and bandwidth requirements of the initial reservation. Unlike the get/del functions, this is meant for internal support and does not require a cookie. It is important to delete the reservation from the network manager point of view BEFORE the expiry is reset. If expiry is set first then the network manager will cause queue timeslices to be split on that boundary leaving dangling queues. */ func (inv *Inventory) yank_res(name *string) (p *gizmos.Pledge, state error) { state = nil p = inv.cache[*name] if p != nil { switch pldg := (*p).(type) { case *gizmos.Pledge_bw: rm_sheep.Baa(2, "resgmgr: yanked reservation: %s", (*p).To_str()) cp := pldg.Clone(*name + ".yank") // clone but DO NOT set conclude time until after network delete! icp := gizmos.Pledge(cp) // must convert to a pledge interface inv.cache[*name+".yank"] = &icp // and then insert the address of the interface inv.cache[*name] = nil // yank original from the list delete(inv.cache, *name) pldg.Set_path_list(nil) // no path list for this pledge ch := make(chan *ipc.Chmsg) defer close(ch) // close it on return req := ipc.Mk_chmsg() req.Send_req(nw_ch, ch, REQ_DEL, cp, nil) // delete from the network point of view req = <-ch // wait for response from network state = req.State // now safe to set these cp.Set_expiry(time.Now().Unix() + 1) // force clone to be expired cp.Reset_pushed() // force it to go out again // not supported for other pledge types } } else { state = fmt.Errorf("no reservation with name: %s", *name) rm_sheep.Baa(2, "resgmgr: unable to yank, no reservation with name: %s", *name) } return }
/* * Parse and react to a POST to /tegu/mirrors/. We expect JSON describing the mirror request, to wit: * { * "start_time": "nnn", // optional * "end_time": "nnn", // required * "output": "<output spec>", // required * "port": [ "port1" , "port2", ...], // required * "vlan": "vlan", // optional * "cookie": "value", // optional * "name": "mirrorname", // optional * } * * Because multiple mirrors may be created as a result, we return an array of JSON results, one for each mirror: * [ * { * "name": "mirrorname", // tegu or user-defined mirror name * "url": "url", // URL to use for DELETE or GET * "error": "err" // error message (if any) * }, * .... * ] */ func mirror_post(in *http.Request, out http.ResponseWriter, data []byte) (code int, msg string) { http_sheep.Baa(5, "Request data: "+string(data)) code = http.StatusOK // 1. Unmarshall the JSON request, check for required fields type req_type struct { Start_time string `json:"start_time"` End_time string `json:"end_time"` // required Output string `json:"output"` // required Port []string `json:"port"` // required Vlan string `json:"vlan"` Cookie string `json:"cookie"` Name string `json:"name"` } var req req_type if err := json.Unmarshal(data, &req); err != nil { code = http.StatusBadRequest msg = "Bad JSON: " + err.Error() return } if req.End_time == "" || req.Output == "" || len(req.Port) == 0 { code = http.StatusBadRequest msg = "Missing a required field." return } // 2. Check start/end times, and VLAN list stime, etime, err := checkTimes(req.Start_time, req.End_time) if err != nil { code = http.StatusBadRequest msg = err.Error() return } err = validVlanList(req.Vlan) if err != nil { code = http.StatusBadRequest msg = err.Error() return } // 3. Generate random name if not given if req.Name == "" { req.Name = generateMirrorName() } else if !validName(req.Name) { code = http.StatusBadRequest msg = "Invalid mirror name: " + req.Name return } // 4. Validate input ports, and assign into groups plist, err := validatePorts(req.Port, req.Name) if err != nil { // no valid ports, give up code = http.StatusBadRequest msg = err.Error() return } // 5. Validate output port newport, err := validateOutputPort(&req.Output) if err != nil { code = http.StatusBadRequest msg = err.Error() return } req.Output = *newport // 6. Make one pledge per mirror, send to reservation mgr, build JSON return string scheme := "http" if isSSL { scheme = "https" } code = http.StatusCreated sep := "\n" bs := bytes.NewBufferString("[") for key, mirror := range *plist { if key != "_badports_" { // Make a pledge phost := key nam := mirror.name res, err := gizmos.Mk_mirror_pledge(mirror.ports, &req.Output, stime, etime, &nam, &req.Cookie, &phost, &req.Vlan) if res != nil { req := ipc.Mk_chmsg() my_ch := make(chan *ipc.Chmsg) // allocate channel for responses to our requests defer close(my_ch) // close it on return gp := gizmos.Pledge(res) // convert to generic pledge to pass req.Send_req(rmgr_ch, my_ch, REQ_DUPCHECK, &gp, nil) // see if we have a duplicate in the cache req = <-my_ch // get response from the network thread if req.Response_data != nil && req.Response_data.(*string) != nil { // response is a pointer to string, if the pointer isn't nil it's a dup rp := req.Response_data.(*string) if rp != nil { http_sheep.Baa(1, "duplicate mirror reservation was dropped") err = fmt.Errorf("reservation duplicates existing reservation: %s", *rp) } } else { req = ipc.Mk_chmsg() ip := gizmos.Pledge(res) // must pass an interface pointer to resmgr req.Send_req(rmgr_ch, my_ch, REQ_ADD, &ip, nil) // network OK'd it, so add it to the inventory req = <-my_ch // wait for completion if req.State == nil { ckptreq := ipc.Mk_chmsg() ckptreq.Send_req(rmgr_ch, nil, REQ_CHKPT, nil, nil) // request a chkpt now, but don't wait on it } else { err = fmt.Errorf("%s", req.State) } } if res_paused { http_sheep.Baa(1, "reservations are paused, accepted reservation will not be pushed until resumed") res.Pause(false) // when paused we must mark the reservation as paused and pushed so it doesn't push until resume received res.Set_pushed() } } else { if err == nil { err = fmt.Errorf("specific reason unknown") // ensure we have something for message } } mirror.err = err } bs.WriteString(fmt.Sprintf(`%s { "name": "%s", `, sep, mirror.name)) bs.WriteString(fmt.Sprintf(`"port": [ `)) sep2 := "" for _, p := range mirror.ports { bs.WriteString(fmt.Sprintf(`%s"%s"`, sep2, p)) sep2 = ", " } bs.WriteString(fmt.Sprintf(` ], `)) if mirror.err == nil { bs.WriteString(fmt.Sprintf(`"url": "%s://%s/tegu/mirrors/%s/"`, scheme, in.Host, mirror.name)) } else { bs.WriteString(fmt.Sprintf(`"error": "%s"`, mirror.err.Error())) } bs.WriteString(" }") sep = ",\n" } bs.WriteString("\n]\n") msg = bs.String() return }