go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/swarming/server/testing/fakesubmit/main.go (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Command fakesubmit submits an RBE reservation for testing fakebot. 16 package main 17 18 import ( 19 "context" 20 "flag" 21 "fmt" 22 "os" 23 "time" 24 25 "github.com/google/uuid" 26 "google.golang.org/grpc" 27 "google.golang.org/grpc/codes" 28 "google.golang.org/grpc/credentials" 29 "google.golang.org/grpc/status" 30 "google.golang.org/protobuf/types/known/anypb" 31 "google.golang.org/protobuf/types/known/timestamppb" 32 33 "go.chromium.org/luci/auth" 34 "go.chromium.org/luci/common/clock" 35 "go.chromium.org/luci/common/errors" 36 "go.chromium.org/luci/common/logging" 37 "go.chromium.org/luci/common/logging/gologger" 38 "go.chromium.org/luci/common/system/signals" 39 "go.chromium.org/luci/hardcoded/chromeinfra" 40 41 "go.chromium.org/luci/swarming/internal/remoteworkers" 42 internalspb "go.chromium.org/luci/swarming/proto/internals" 43 ) 44 45 var ( 46 pool = flag.String("pool", "local-test", "Value for `pool` dimension") 47 rbeInstance = flag.String("rbe-instance", "projects/chromium-swarm-dev/instances/default_instance", "Full RBE instance name to use for tests") 48 expiration = flag.Duration("expiration", 10*time.Minute, "Task expiration time") 49 tasks = flag.Int("tasks", 1, "How many tasks to submit in parallel") 50 noop = flag.Bool("noop", false, "If set, mark tasks as noop") 51 taskIDPrefix = flag.String("task-id-prefix", "", "Prefix for reservation IDs") 52 ) 53 54 func main() { 55 flag.Parse() 56 ctx := gologger.StdConfig.Use(context.Background()) 57 if err := run(ctx); err != nil { 58 errors.Log(ctx, err) 59 os.Exit(1) 60 } 61 } 62 63 func run(ctx context.Context) error { 64 creds, err := auth.NewAuthenticator(ctx, auth.SilentLogin, chromeinfra.SetDefaultAuthOptions(auth.Options{ 65 Scopes: []string{ 66 "https://www.googleapis.com/auth/cloud-platform", 67 "https://www.googleapis.com/auth/userinfo.email", 68 }, 69 })).PerRPCCredentials() 70 if err != nil { 71 return err 72 } 73 74 cc, err := grpc.DialContext(ctx, "remotebuildexecution.googleapis.com:443", 75 grpc.WithTransportCredentials(credentials.NewTLS(nil)), 76 grpc.WithPerRPCCredentials(creds), 77 grpc.WithBlock(), 78 ) 79 if err != nil { 80 return err 81 } 82 rbe := remoteworkers.NewReservationsClient(cc) 83 84 loopCtx, cancel := context.WithCancel(ctx) 85 defer cancel() 86 signals.HandleInterrupt(func() { 87 logging.Infof(ctx, "Got termination signal") 88 cancel() 89 }) 90 91 if *taskIDPrefix == "" { 92 *taskIDPrefix = uuid.New().String() 93 } 94 95 type execResult struct { 96 taskID string 97 start time.Time 98 end time.Time 99 reservation *remoteworkers.Reservation 100 err error 101 } 102 results := make(chan execResult, *tasks) 103 104 for i := 0; i < *tasks; i++ { 105 i := i 106 go func() { 107 taskID := fmt.Sprintf("%s-%04d", *taskIDPrefix, i) 108 start := clock.Now(ctx) 109 reservation, err := execTask(ctx, loopCtx, rbe, taskID) 110 results <- execResult{ 111 taskID: taskID, 112 start: start, 113 end: clock.Now(ctx), 114 reservation: reservation, 115 err: err, 116 } 117 }() 118 } 119 120 for i := 0; i < *tasks; i++ { 121 res := <-results 122 switch { 123 case res.err != nil: 124 logging.Errorf(ctx, "%s: %s", res.taskID, res.err) 125 case res.reservation == nil: 126 logging.Warningf(ctx, "%s: canceled", res.taskID) 127 default: 128 reservation := res.reservation 129 if reservation.Status.GetCode() != 0 { 130 logging.Infof(ctx, "%s: %s %s", res.taskID, reservation.AssignedBotId, status.FromProto(reservation.Status)) 131 } else { 132 logging.Infof(ctx, "%s: %s", res.taskID, reservation.AssignedBotId) 133 } 134 } 135 } 136 137 return nil 138 } 139 140 func execTask(ctx, loopCtx context.Context, rbe remoteworkers.ReservationsClient, taskID string) (*remoteworkers.Reservation, error) { 141 reservationName := fmt.Sprintf("%s/reservations/%s", *rbeInstance, taskID) 142 143 payload, err := anypb.New(&internalspb.TaskPayload{ 144 TaskId: taskID, 145 Noop: *noop, 146 }) 147 if err != nil { 148 return nil, err 149 } 150 151 reservation, err := rbe.CreateReservation(ctx, &remoteworkers.CreateReservationRequest{ 152 Parent: *rbeInstance, 153 Reservation: &remoteworkers.Reservation{ 154 Name: reservationName, 155 Payload: payload, 156 ExpireTime: timestamppb.New(time.Now().Add(*expiration)), 157 Constraints: []*remoteworkers.Constraint{ 158 {Key: "label:pool", AllowedValues: []string{*pool}}, 159 }, 160 }, 161 }) 162 if status.Code(err) == codes.AlreadyExists { 163 reservation, err = rbe.GetReservation(ctx, &remoteworkers.GetReservationRequest{ 164 Name: reservationName, 165 }) 166 if err != nil { 167 return nil, errors.Annotate(err, "GetReservation").Err() 168 } 169 } else if err != nil { 170 return nil, errors.Annotate(err, "CreateReservation").Err() 171 } 172 173 for loopCtx.Err() == nil { 174 if reservation.State == remoteworkers.ReservationState_RESERVATION_COMPLETED || reservation.State == remoteworkers.ReservationState_RESERVATION_CANCELLED { 175 return reservation, nil 176 } 177 reservation, err = rbe.GetReservation(loopCtx, &remoteworkers.GetReservationRequest{ 178 Name: reservationName, 179 WaitSeconds: 60, 180 }) 181 if err != nil { 182 if loopCtx.Err() != nil { 183 break 184 } 185 return nil, err 186 } 187 } 188 189 _, err = rbe.CancelReservation(ctx, &remoteworkers.CancelReservationRequest{ 190 Name: reservationName, 191 Intent: remoteworkers.CancelReservationIntent_ANY, 192 }) 193 if err != nil { 194 return nil, err 195 } 196 return nil, nil 197 }