| Index: milo/appengine/swarming/buildinfo.go
|
| diff --git a/milo/appengine/swarming/buildinfo.go b/milo/appengine/swarming/buildinfo.go
|
| index abb04252bc85fdde1d6f5514a61f2f37e40eb109..1dd051d9eb2c542efc076ead78e134ca9eea17e1 100644
|
| --- a/milo/appengine/swarming/buildinfo.go
|
| +++ b/milo/appengine/swarming/buildinfo.go
|
| @@ -5,9 +5,12 @@
|
| package swarming
|
|
|
| import (
|
| + "strconv"
|
| "strings"
|
| + "unicode/utf8"
|
|
|
| swarming "github.com/luci/luci-go/common/api/swarming/swarming/v1"
|
| + "github.com/luci/luci-go/common/errors"
|
| "github.com/luci/luci-go/common/logging"
|
| miloProto "github.com/luci/luci-go/common/proto/milo"
|
| "github.com/luci/luci-go/grpc/grpcutil"
|
| @@ -86,7 +89,7 @@ func (p *BuildInfoProvider) GetBuildInfo(c context.Context, req *milo.BuildInfoR
|
| // Determine the LogDog annotation stream path for this Swarming task.
|
| //
|
| // On failure, will return a gRPC error.
|
| - as, err := resolveLogDogAnnotations(c, fr.req, projectHint, host, req.Task)
|
| + as, err := resolveLogDogAnnotations(c, fr.req, projectHint, host, req.Task, fr.res.TryNumber)
|
| if err != nil {
|
| logging.WithError(err).Warningf(c, "Failed to get annotation stream parameters.")
|
| return nil, err
|
| @@ -96,6 +99,11 @@ func (p *BuildInfoProvider) GetBuildInfo(c context.Context, req *milo.BuildInfoR
|
| return nil, grpcutil.Internal
|
| }
|
|
|
| + logging.Fields{
|
| + "project": as.Project,
|
| + "path": as.Path,
|
| + }.Infof(c, "Resolved annotation stream.")
|
| +
|
| client, err := p.newLogdogClient(c)
|
| if err != nil {
|
| logging.WithError(err).Errorf(c, "Failed to create LogDog client.")
|
| @@ -136,7 +144,7 @@ func (p *BuildInfoProvider) GetBuildInfo(c context.Context, req *milo.BuildInfoR
|
| // endpoint, though. All of the nastiness here should be replaced with something
|
| // more elegant once that becomes available. In the meantime...
|
| func resolveLogDogAnnotations(c context.Context, sr *swarming.SwarmingRpcsTaskRequest, projectHint cfgtypes.ProjectName,
|
| - host, taskID string) (*logdog.AnnotationStream, error) {
|
| + host, taskID string, tryNumber int64) (*logdog.AnnotationStream, error) {
|
|
|
| // If this is a Kitchen command, maybe we can infer our LogDog project from
|
| // the command-line.
|
| @@ -165,7 +173,17 @@ func resolveLogDogAnnotations(c context.Context, sr *swarming.SwarmingRpcsTaskRe
|
| //
|
| // This is an implementation of:
|
| // https://chromium.googlesource.com/infra/infra/+/a7032e3e240d4b81a1912bfaf29a20d02f665cc1/go/src/infra/tools/kitchen/cook_logdog.go#129
|
| - prefix, err := types.MakeStreamName("", "swarm", host, taskID)
|
| + runID, err := getRunID(taskID, tryNumber)
|
| + if err != nil {
|
| + logging.Fields{
|
| + logging.ErrorKey: err,
|
| + "taskID": taskID,
|
| + "tryNumber": tryNumber,
|
| + }.Errorf(c, "Failed to get Run ID for task/try.")
|
| + return nil, grpcutil.Internal
|
| + }
|
| +
|
| + prefix, err := types.MakeStreamName("", "swarm", host, runID)
|
| if err != nil {
|
| logging.WithError(err).Errorf(c, "Failed to generate Swarming prefix.")
|
| return nil, grpcutil.Internal
|
| @@ -197,3 +215,33 @@ func getLogDogProjectFromKitchen(cmd []string) (proj cfgtypes.ProjectName, isKit
|
| }
|
| return
|
| }
|
| +
|
| +// getRunID converts a Swarming task ID and try number into a Swarming Run ID.
|
| +//
|
| +// The run ID is a permutation of the last four bits of the Swarming Task ID.
|
| +// Therefore, we chop it off of the string, mutate it, and then add it back.
|
| +//
|
| +// TODO(dnj): Replace this with Swarming API call once finished.
|
| +func getRunID(taskID string, tryNumber int64) (string, error) {
|
| + // Slice off the last character form the task ID.
|
| + if len(taskID) == 0 {
|
| + return "", errors.New("swarming task ID is empty")
|
| + }
|
| +
|
| + // Parse "tryNumber" as a hex string.
|
| + if tryNumber < 0 || tryNumber > 0x0F {
|
| + return "", errors.Reason("try number %(try)d exceeds 4 bits").
|
| + D("try", tryNumber).
|
| + Err()
|
| + }
|
| +
|
| + lastChar, lastCharSize := utf8.DecodeLastRuneInString(taskID)
|
| + v, err := strconv.ParseUint(string(lastChar), 16, 8)
|
| + if err != nil {
|
| + return "", errors.Annotate(err).Reason("failed to parse hex from rune: %(rune)r").
|
| + D("rune", lastChar).
|
| + Err()
|
| + }
|
| +
|
| + return taskID[:len(taskID)-lastCharSize] + strconv.FormatUint((v|uint64(tryNumber)), 16), nil
|
| +}
|
|
|