1// Copyright 2019 The Pigweed Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may not 4// use this file except in compliance with the License. You may obtain a copy of 5// the License at 6// 7// https://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, WITHOUT 11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12// License for the specific language governing permissions and limitations under 13// the License. 14package main 15 16import ( 17 "context" 18 "errors" 19 "flag" 20 "fmt" 21 "log" 22 "os" 23 "time" 24 25 "google.golang.org/grpc" 26 "google.golang.org/grpc/codes" 27 "google.golang.org/grpc/status" 28 29 pb "pigweed/proto/pw_target_runner/target_runner_pb" 30) 31 32// Client is a gRPC client that communicates with a TargetRunner service. 33type Client struct { 34 conn *grpc.ClientConn 35} 36 37// NewClient creates a gRPC client which connects to a gRPC server hosted at the 38// specified address. 39func NewClient(host string, port int) (*Client, error) { 40 // The server currently only supports running locally over an insecure 41 // connection. 42 // TODO(frolv): Investigate adding TLS support to the server and client. 43 opts := []grpc.DialOption{ 44 grpc.WithInsecure(), 45 grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(20 * 1024 * 1024)), 46 } 47 48 conn, err := grpc.Dial(fmt.Sprintf("%s:%d", host, port), opts...) 49 if err != nil { 50 return nil, err 51 } 52 53 return &Client{conn}, nil 54} 55 56// RunBinary sends a RunBinary RPC to the target runner service. 57func (c *Client) RunBinary(path string) error { 58 data, err := os.ReadFile(path) 59 if err != nil { 60 return err 61 } 62 63 client := pb.NewTargetRunnerClient(c.conn) 64 req := &pb.RunBinaryRequest{Binary: &pb.RunBinaryRequest_TestBinary{TestBinary: data}} 65 66 res, err := client.RunBinary(context.Background(), req) 67 if err != nil { 68 return err 69 } 70 71 fmt.Printf("%s\n", path) 72 fmt.Printf( 73 "Queued for %v, ran in %v\n\n", 74 time.Duration(res.QueueTimeNs), 75 time.Duration(res.RunTimeNs), 76 ) 77 fmt.Println(string(res.Output)) 78 79 if res.Result != pb.RunStatus_SUCCESS { 80 return errors.New("Binary run was unsuccessful") 81 } 82 83 return nil 84} 85 86func main() { 87 hostPtr := flag.String("host", "localhost", "Server host") 88 portPtr := flag.Int("port", 8080, "Server port") 89 pathPtr := flag.String("binary", "", "Path to executable file") 90 serverSuggestionPtr := flag.String("server_suggestion", "", "Suggested command to display if no server is available.") 91 92 flag.Parse() 93 94 if *pathPtr == "" { 95 log.Fatalf("Must provide -binary option") 96 } 97 98 cli, err := NewClient(*hostPtr, *portPtr) 99 if err != nil { 100 log.Fatalf("Failed to create gRPC client: %v", err) 101 } 102 103 if err := cli.RunBinary(*pathPtr); err != nil { 104 log.Println("Failed to run executable on target:") 105 log.Println("") 106 107 s, _ := status.FromError(err) 108 if s.Code() == codes.Unavailable { 109 log.Println(" No pw_target_runner_server is running.") 110 log.Println(" Check that a server has been started for your target.") 111 if *serverSuggestionPtr != "" { 112 log.Println(" Consider starting a test server with: ", *serverSuggestionPtr) 113 } 114 } else { 115 log.Printf(" %v\n", err) 116 } 117 118 log.Fatal("") 119 } 120} 121