github.com/kubeshop/testkube@v1.17.23/pkg/cloud/data/artifact/uploader.go (about) 1 package artifact 2 3 import ( 4 "context" 5 "crypto/tls" 6 "encoding/json" 7 "io" 8 "net/http" 9 10 "github.com/kubeshop/testkube/pkg/api/v1/testkube" 11 12 "github.com/kubeshop/testkube/pkg/log" 13 14 "github.com/pkg/errors" 15 16 "github.com/kubeshop/testkube/pkg/cloud/data/executor" 17 "github.com/kubeshop/testkube/pkg/executor/scraper" 18 ) 19 20 type CloudUploader struct { 21 executor executor.Executor 22 // skipVerify is used to skip TLS verification when artifacts 23 skipVerify bool 24 } 25 26 func NewCloudUploader(executor executor.Executor, skipVerify bool) *CloudUploader { 27 return &CloudUploader{executor: executor, skipVerify: skipVerify} 28 } 29 30 func (u *CloudUploader) Upload(ctx context.Context, object *scraper.Object, execution testkube.Execution) error { 31 log.DefaultLogger.Infow("cloud uploader is requesting signed URL", "file", object.Name, "folder", execution.Id, "size", object.Size) 32 req := &PutObjectSignedURLRequest{ 33 Object: object.Name, 34 ExecutionID: execution.Id, 35 TestName: execution.TestName, 36 TestSuiteName: execution.TestSuiteName, 37 } 38 signedURL, err := u.getSignedURL(ctx, req) 39 if err != nil { 40 return errors.Wrapf(err, "failed to get signed URL for object [%s]", req.Object) 41 } 42 43 log.DefaultLogger.Infow("cloud uploader is uploading file", "file", object.Name, "folder", req.ExecutionID, "size", object.Size) 44 if err := u.putObject(ctx, signedURL, object.Data); err != nil { 45 return errors.Wrapf(err, "failed to send object [%s] to cloud", req.Object) 46 } 47 48 return nil 49 } 50 51 func (u *CloudUploader) getSignedURL(ctx context.Context, req *PutObjectSignedURLRequest) (string, error) { 52 response, err := u.executor.Execute(ctx, CmdScraperPutObjectSignedURL, req) 53 if err != nil { 54 return "", err 55 } 56 var commandResponse PutObjectSignedURLResponse 57 if err := json.Unmarshal(response, &commandResponse); err != nil { 58 return "", err 59 } 60 return commandResponse.URL, nil 61 } 62 63 func (u *CloudUploader) putObject(ctx context.Context, url string, data io.Reader) error { 64 req, err := http.NewRequestWithContext(ctx, http.MethodPut, url, data) 65 if err != nil { 66 return err 67 } 68 req.Header.Set("Content-Type", "application/octet-stream") 69 tr := http.DefaultTransport.(*http.Transport).Clone() 70 tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: u.skipVerify} 71 client := &http.Client{Transport: tr} 72 rsp, err := client.Do(req) 73 if err != nil { 74 return errors.Wrap(err, "failed to send file to cloud") 75 } 76 if rsp.StatusCode != http.StatusOK { 77 return errors.Errorf("error getting file from presigned url: expected 200 OK response code, got %d", rsp.StatusCode) 78 } 79 return nil 80 } 81 82 func (u *CloudUploader) Close() error { 83 return u.executor.Close() 84 }