예제 #1
0
//Error is used when there were any errors in building the test
func (Response) Error(req *http.Request, args *rpc.BuilderResponse, resp *rpc.None) (err error) {
	//wrap our error on the way out
	defer rpc.Wrap(&err)

	//create the context
	ctx := httputil.NewContext(req)
	defer ctx.Close()

	//get the key of the work item
	key := bson.ObjectIdHex(args.Key)

	ops := []txn.Op{{ //make sure we have the given work item
		C:  "Work",
		Id: key,
		Assert: bson.M{
			"status":          entities.WorkStatusProcessing,
			"attemptlog.0.id": bson.ObjectIdHex(args.ID),
			"revision":        args.WorkRev,
		},
		Update: bson.M{
			"$set": bson.M{"status": entities.WorkStatusCompleted},
			"$inc": bson.M{"revision": 1},
		},
	}, { //insert the work result
		C:  "WorkResult",
		Id: bson.NewObjectId(),
		Insert: entities.WorkResult{
			WorkID:   key,
			Success:  false,
			Revision: args.Revision,
			RevDate:  args.RevDate,
			When:     time.Now(),
			Error:    args.Error,
		},
	}}

	//run the transaction
	err = ctx.R.Run(ops, bson.NewObjectId(), nil)
	if err == txn.ErrAborted {
		ctx.Infof("Lost the race inserting result.")
		err = nil
	}

	return
}
예제 #2
0
//Remove removes a service from the tracker.
func (Tracker) Remove(req *http.Request, args *rpc.RemoveArgs, rep *rpc.None) (err error) {
	//wrap our error on the way out
	defer rpc.Wrap(&err)

	//create our context
	ctx := httputil.NewContext(req)
	defer ctx.Close()
	ctx.Infof("Got a remove request from %s: %+v", req.RemoteAddr, args)

	//get the key from the argument
	key := bson.ObjectIdHex(args.Key)

	//make sure its an entity
	if !isEntity(args.Kind) {
		err = rpc.Errorf("kind is not Builder or Runner")
		return
	}

	//remove it from the database
	err = ctx.DB.C(args.Kind).Remove(bson.M{"_id": key})
	return
}
예제 #3
0
//Announce adds the given service into the tracker pool.
func (Tracker) Announce(req *http.Request, args *rpc.AnnounceArgs, rep *rpc.AnnounceReply) (err error) {
	//wrap our error on the way out
	defer rpc.Wrap(&err)

	if err = verify(args); err != nil {
		return
	}

	ctx := httputil.NewContext(req)
	defer ctx.Close()
	ctx.Infof("Got announce request from %s: %+v", req.RemoteAddr, args)

	//ping them to make sure we can make valid rpc calls
	cl := client.New(args.URL, http.DefaultClient, client.JsonCodec)
	err = cl.Call("Pinger.Ping", nil, new(rpc.None))
	if err != nil {
		ctx.Infof("Failed to Ping the announce.")
		return
	}

	//create the entity
	var e interface{}

	//make sure we have a nonzero seed
	var seed int64
	for seed == 0 {
		seed = rand.Int63()
	}
	key := bson.NewObjectId()
	switch args.Type {
	case "Builder":
		e = &Builder{
			ID:     key,
			GOOS:   args.GOOS,
			GOARCH: args.GOARCH,
			URL:    args.URL,
			Seed:   seed,
		}
	case "Runner":
		e = &Runner{
			ID:     key,
			GOOS:   args.GOOS,
			GOARCH: args.GOARCH,
			URL:    args.URL,
			Seed:   seed,
		}
	default:
		panic("unreachable")
	}

	//TODO(zeebo): check if we have the URL already and grab that key to update

	//save the service in the database
	if err = ctx.DB.C(args.Type).Insert(e); err != nil {
		return
	}

	//return the hex representation of the key
	rep.Key = key.Hex()
	return
}
예제 #4
0
//Post is the rpc method that the Runner uses to give a response about an item.
func (Response) Post(req *http.Request, args *rpc.RunnerResponse, resp *rpc.None) (err error) {
	//wrap our error on the way out
	defer rpc.Wrap(&err)

	//create our context
	ctx := httputil.NewContext(req)
	defer ctx.Close()

	//build the keys we need to reference
	key := bson.ObjectIdHex(args.Key)
	wkey := bson.NewObjectId()

	ops := []txn.Op{{ //make sure we have the given work item
		C:  "Work",
		Id: key,
		Assert: bson.M{
			"status":          entities.WorkStatusProcessing,
			"attemptlog.0.id": bson.ObjectIdHex(args.ID),
			"revision":        args.WorkRev,
		},
		Update: bson.M{
			"$set": bson.M{"status": entities.WorkStatusCompleted},
			"$inc": bson.M{"revision": 1},
		},
	}, { //insert the work result
		C:  "WorkResult",
		Id: wkey,
		Insert: entities.WorkResult{
			WorkID:   key,
			Success:  true,
			Revision: args.Revision,
			RevDate:  args.RevDate,
			When:     time.Now(),
		},
	}}

	//operations for notifications
	var nots []txn.Op

	//store the test results
	for _, out := range args.Tests {

		//get the status from the output type and output
		var status string
		switch out.Type {
		case rpc.OutputSuccess:
			if strings.HasSuffix(out.Output, "\nPASS\n") {
				status = entities.TestStatusPass
			} else {
				status = entities.TestStatusFail
			}
		case rpc.OutputWontBuild:
			status = entities.TestStatusWontBuild
		case rpc.OutputError:
			status = entities.TestStatusError
		default:
			err = fmt.Errorf("unknown output type: %s", out.Type)
			return
		}

		//add the test result to the operation
		tid := bson.NewObjectId()
		ops = append(ops, txn.Op{
			C:  "TestResult",
			Id: tid,
			Insert: entities.TestResult{
				WorkResultID: wkey,
				ImportPath:   out.ImportPath,
				Revision:     args.Revision,
				RevDate:      args.RevDate,
				When:         time.Now(),
				Output:       out.Output,
				Status:       status,
			},
		})

		//skip if we don't have a notification
		if out.Config.NotifyOn == "" {
			continue
		}

		//add in the notification
		nots = append(nots, txn.Op{
			C:  "Notification",
			Id: bson.NewObjectId(),
			Insert: entities.Notification{
				Test:   tid,
				Config: out.Config,
				Status: entities.NotifStatusWaiting,
			},
		})

	}

	//append the notification operations
	ops = append(ops, nots...)

	//run the transaction
	err = ctx.R.Run(ops, bson.NewObjectId(), nil)
	if err == txn.ErrAborted {
		ctx.Infof("Lost the race inserting result.")
		err = nil
	}

	//tell it to dispatch notifications
	if len(nots) > 0 {
		go http.Get(httputil.Absolute("/notifications/dispatch"))
	}

	return
}