internal/gomote: add swarming instance alive
This change adds the instance alive endpoint to the swarming gomote
implementation.
Fixes golang/go#63779
Change-Id: I7e6120df8a7c5b9f87465c7c9f74a74f37b34a07
Reviewed-on: https://go-review.googlesource.com/c/build/+/537901
Auto-Submit: Carlos Amedee <carlos@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/internal/gomote/swarming.go b/internal/gomote/swarming.go
index f894eed..7586f32 100644
--- a/internal/gomote/swarming.go
+++ b/internal/gomote/swarming.go
@@ -244,6 +244,27 @@
return nil
}
+// InstanceAlive will ensure that the gomote instance is still alive and will extend the timeout. The requester must be authenticated.
+func (ss *SwarmingServer) InstanceAlive(ctx context.Context, req *protos.InstanceAliveRequest) (*protos.InstanceAliveResponse, error) {
+ creds, err := access.IAPFromContext(ctx)
+ if err != nil {
+ log.Printf("InstanceAlive access.IAPFromContext(ctx) = nil, %s", err)
+ return nil, status.Errorf(codes.Unauthenticated, "request does not contain the required authentication")
+ }
+ if req.GetGomoteId() == "" {
+ return nil, status.Errorf(codes.InvalidArgument, "invalid gomote ID")
+ }
+ _, err = ss.session(req.GetGomoteId(), creds.ID)
+ if err != nil {
+ // the helper function returns meaningful GRPC error.
+ return nil, err
+ }
+ if err := ss.buildlets.RenewTimeout(req.GetGomoteId()); err != nil {
+ return nil, status.Errorf(codes.Internal, "unable to renew timeout")
+ }
+ return &protos.InstanceAliveResponse{}, nil
+}
+
// ListSwarmingBuilders lists all of the swarming builders which run for gotip. The requester must be authenticated.
func (ss *SwarmingServer) ListSwarmingBuilders(ctx context.Context, req *protos.ListSwarmingBuildersRequest) (*protos.ListSwarmingBuildersResponse, error) {
_, err := access.IAPFromContext(ctx)
diff --git a/internal/gomote/swarming_test.go b/internal/gomote/swarming_test.go
index ca705a4..2c4f15b 100644
--- a/internal/gomote/swarming_test.go
+++ b/internal/gomote/swarming_test.go
@@ -418,6 +418,75 @@
}
}
+func TestSwarmingInstanceAlive(t *testing.T) {
+ client := setupGomoteSwarmingTest(t, context.Background(), mockSwarmClientSimple())
+ gomoteID := mustCreateSwarmingInstance(t, client, fakeIAP())
+ req := &protos.InstanceAliveRequest{
+ GomoteId: gomoteID,
+ }
+ ctx := access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP())
+ got, err := client.InstanceAlive(ctx, req)
+ if err != nil {
+ t.Fatalf("client.InstanceAlive(ctx, %v) = %v, %s; want no error", req, got, err)
+ }
+}
+
+func TestSwarmingInstanceAliveError(t *testing.T) {
+ // This test will create a gomote instance and attempt to call InstanceAlive.
+ // If overrideID is set to true, the test will use a different gomoteID than
+ // the one created for the test.
+ testCases := []struct {
+ desc string
+ ctx context.Context
+ overrideID bool
+ gomoteID string // Used iff overrideID is true.
+ wantCode codes.Code
+ }{
+ {
+ desc: "unauthenticated request",
+ ctx: context.Background(),
+ wantCode: codes.Unauthenticated,
+ },
+ {
+ desc: "missing gomote id",
+ ctx: access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP()),
+ overrideID: true,
+ wantCode: codes.InvalidArgument,
+ },
+ {
+ desc: "gomote does not exist",
+ ctx: access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP()),
+ overrideID: true,
+ gomoteID: "xyz",
+ wantCode: codes.NotFound,
+ },
+ {
+ desc: "gomote is not owned by caller",
+ ctx: access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAPWithUser("user-x", "email-y")),
+ wantCode: codes.PermissionDenied,
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ client := setupGomoteSwarmingTest(t, context.Background(), mockSwarmClientSimple())
+ gomoteID := mustCreateSwarmingInstance(t, client, fakeIAP())
+ if tc.overrideID {
+ gomoteID = tc.gomoteID
+ }
+ req := &protos.InstanceAliveRequest{
+ GomoteId: gomoteID,
+ }
+ got, err := client.InstanceAlive(tc.ctx, req)
+ if err != nil && status.Code(err) != tc.wantCode {
+ t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
+ }
+ if err == nil {
+ t.Fatalf("client.InstanceAlive(ctx, %v) = %v, nil; want error", req, got)
+ }
+ })
+ }
+}
+
func TestSwarmingListInstance(t *testing.T) {
client := setupGomoteSwarmingTest(t, context.Background(), mockSwarmClientSimple())
ctx := access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP())