github.com/kubeshop/testkube@v1.17.23/pkg/api/v1/client/cloud_client.go (about) 1 package client 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "os" 9 "path/filepath" 10 "strings" 11 12 "github.com/pkg/errors" 13 ) 14 15 func NewCloudClient[A All](httpClient *http.Client, apiURI, apiPathPrefix string) CloudClient[A] { 16 if apiPathPrefix == "" { 17 apiPathPrefix = "/" + Version 18 } 19 20 return CloudClient[A]{ 21 client: httpClient, 22 sseClient: httpClient, 23 apiURI: apiURI, 24 apiPathPrefix: apiPathPrefix, 25 DirectClient: NewDirectClient[A](httpClient, apiURI, apiPathPrefix), 26 } 27 } 28 29 // CLoudClient is almost the same as Direct client, but has different GetFile method 30 // which returns a download URL for the artifact instead of downloading it. 31 type CloudClient[A All] struct { 32 client *http.Client 33 sseClient *http.Client 34 apiURI string 35 apiPathPrefix string 36 DirectClient[A] 37 } 38 39 type ArtifactURL struct { 40 // Download URL for the artifact. 41 URL string `json:"url"` 42 } 43 44 // GetFile, in cloud we need to call non 45 func (t CloudClient[A]) GetFile(uri, fileName, destination string, params map[string][]string) (name string, err error) { 46 47 cloudURI := strings.Replace(uri, "/agent", "", -1) 48 req, err := http.NewRequest(http.MethodGet, cloudURI, nil) 49 if err != nil { 50 return "", err 51 } 52 53 q := req.URL.Query() 54 for key, values := range params { 55 for _, value := range values { 56 if value != "" { 57 q.Add(key, value) 58 } 59 } 60 } 61 req.URL.RawQuery = q.Encode() 62 63 resp, err := t.client.Do(req) 64 if err != nil { 65 return name, err 66 } 67 defer resp.Body.Close() 68 69 if resp.StatusCode > 299 { 70 return name, fmt.Errorf("error: %d", resp.StatusCode) 71 } 72 73 var artifactURL ArtifactURL 74 err = json.NewDecoder(resp.Body).Decode(&artifactURL) 75 if err != nil { 76 return "", err 77 } 78 79 req, err = http.NewRequest(http.MethodGet, artifactURL.URL, nil) 80 if err != nil { 81 return "", err 82 } 83 resp, err = t.client.Do(req) 84 if err != nil { 85 return name, err 86 } 87 defer resp.Body.Close() 88 89 target := filepath.Join(destination, fileName) 90 dir := filepath.Dir(target) 91 if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) { 92 if err = os.MkdirAll(dir, os.ModePerm); err != nil { 93 return name, err 94 } 95 } else if err != nil { 96 return name, err 97 } 98 99 f, err := os.Create(target) 100 if err != nil { 101 return name, err 102 } 103 104 if _, err = io.Copy(f, resp.Body); err != nil { 105 return name, err 106 } 107 108 if err = t.responseError(resp); err != nil { 109 return name, fmt.Errorf("api/download-file returned error: %w", err) 110 } 111 112 return f.Name(), nil 113 }