github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/api/etl.go (about) 1 // Package api provides native Go-based API/SDK over HTTP(S). 2 /* 3 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package api 6 7 import ( 8 "fmt" 9 "io" 10 "net/http" 11 "net/url" 12 "strconv" 13 14 "github.com/NVIDIA/aistore/api/apc" 15 "github.com/NVIDIA/aistore/cmn" 16 "github.com/NVIDIA/aistore/cmn/cos" 17 "github.com/NVIDIA/aistore/cmn/debug" 18 "github.com/NVIDIA/aistore/ext/etl" 19 ) 20 21 // Initiate custom ETL workload by executing one of the documented `etl.InitMsg` 22 // message types. 23 // The API call results in deploying multiple ETL containers (K8s pods): 24 // one container per storage target. 25 // Returns xaction ID if successful, an error otherwise. 26 func ETLInit(bp BaseParams, msg etl.InitMsg) (xid string, err error) { 27 bp.Method = http.MethodPut 28 reqParams := AllocRp() 29 { 30 reqParams.BaseParams = bp 31 reqParams.Path = apc.URLPathETL.S 32 reqParams.Body = cos.MustMarshal(msg) 33 } 34 _, err = reqParams.doReqStr(&xid) 35 FreeRp(reqParams) 36 return 37 } 38 39 func ETLList(bp BaseParams) (list []etl.Info, err error) { 40 bp.Method = http.MethodGet 41 reqParams := AllocRp() 42 { 43 reqParams.BaseParams = bp 44 reqParams.Path = apc.URLPathETL.S 45 } 46 _, err = reqParams.DoReqAny(&list) 47 FreeRp(reqParams) 48 return 49 } 50 51 func ETLGetInitMsg(params BaseParams, etlName string) (etl.InitMsg, error) { 52 params.Method = http.MethodGet 53 reqParams := AllocRp() 54 { 55 reqParams.BaseParams = params 56 reqParams.Path = apc.URLPathETL.Join(etlName) 57 } 58 r, size, err := reqParams.doReader() 59 FreeRp(reqParams) 60 if err != nil { 61 return nil, err 62 } 63 defer cos.Close(r) 64 65 b, err := io.ReadAll(r) 66 if err != nil { 67 return nil, fmt.Errorf("failed to read response: %w", err) 68 } 69 debug.Assert(size < 0 || size == int64(len(b)), size, " != ", len(b)) 70 return etl.UnmarshalInitMsg(b) 71 } 72 73 func ETLLogs(bp BaseParams, etlName string, targetID ...string) (logs etl.LogsByTarget, err error) { 74 bp.Method = http.MethodGet 75 var path string 76 if len(targetID) > 0 && targetID[0] != "" { 77 path = apc.URLPathETL.Join(etlName, apc.ETLLogs, targetID[0]) 78 } else { 79 path = apc.URLPathETL.Join(etlName, apc.ETLLogs) 80 } 81 reqParams := AllocRp() 82 { 83 reqParams.BaseParams = bp 84 reqParams.Path = path 85 } 86 _, err = reqParams.DoReqAny(&logs) 87 FreeRp(reqParams) 88 return 89 } 90 91 func ETLMetrics(params BaseParams, etlName string) (healths etl.CPUMemByTarget, err error) { 92 params.Method = http.MethodGet 93 path := apc.URLPathETL.Join(etlName, apc.ETLMetrics) 94 reqParams := AllocRp() 95 { 96 reqParams.BaseParams = params 97 reqParams.Path = path 98 } 99 _, err = reqParams.DoReqAny(&healths) 100 FreeRp(reqParams) 101 return 102 } 103 104 func ETLHealth(params BaseParams, etlName string) (healths etl.HealthByTarget, err error) { 105 params.Method = http.MethodGet 106 path := apc.URLPathETL.Join(etlName, apc.ETLHealth) 107 reqParams := AllocRp() 108 { 109 reqParams.BaseParams = params 110 reqParams.Path = path 111 } 112 _, err = reqParams.DoReqAny(&healths) 113 FreeRp(reqParams) 114 return 115 } 116 117 func ETLDelete(bp BaseParams, etlName string) (err error) { 118 bp.Method = http.MethodDelete 119 reqParams := AllocRp() 120 { 121 reqParams.BaseParams = bp 122 reqParams.Path = apc.URLPathETL.Join(etlName) 123 } 124 err = reqParams.DoRequest() 125 FreeRp(reqParams) 126 return 127 } 128 129 func ETLStop(bp BaseParams, etlName string) (err error) { 130 return etlPostAction(bp, etlName, apc.ETLStop) 131 } 132 133 func ETLStart(bp BaseParams, etlName string) (err error) { 134 return etlPostAction(bp, etlName, apc.ETLStart) 135 } 136 137 func etlPostAction(bp BaseParams, etlName, action string) (err error) { 138 bp.Method = http.MethodPost 139 reqParams := AllocRp() 140 { 141 reqParams.BaseParams = bp 142 reqParams.Path = apc.URLPathETL.Join(etlName, action) 143 } 144 err = reqParams.DoRequest() 145 FreeRp(reqParams) 146 return 147 } 148 149 // TODO: add ETL-specific query param and change the examples/docs (!4455) 150 func ETLObject(bp BaseParams, etlName string, bck cmn.Bck, objName string, w io.Writer) (err error) { 151 _, err = GetObject(bp, bck, objName, &GetArgs{ 152 Writer: w, 153 Query: url.Values{apc.QparamETLName: []string{etlName}}, 154 }) 155 return 156 } 157 158 // Transform src bucket => dst bucket, i.e.: 159 // - visit all (matching) source objects; for each object: 160 // - read it, transform using the specified (ID-ed) ETL, and write the result to dst bucket 161 // 162 // `fltPresence` applies exclusively to remote `bckFrom` (is ignored otherwise) 163 // and is one of: { apc.FltExists, apc.FltPresent, ... } - for complete enum, see api/apc/query.go 164 // Namely: 165 // * apc.FltExists - copy all objects, including those that are not (present) in AIS 166 // * apc.FltPresent - copy the current `bckFrom` content in the cluster (default) 167 // * apc.FltExistsOutside - copy only those remote objects that are not (present) in AIS 168 // 169 // msg.Prefix, if specified, applies always and regardless. 170 // 171 // Returns xaction ID if successful, an error otherwise. See also: api.CopyBucket 172 func ETLBucket(bp BaseParams, bckFrom, bckTo cmn.Bck, msg *apc.TCBMsg, fltPresence ...int) (xid string, err error) { 173 if err = bckTo.Validate(); err != nil { 174 return 175 } 176 bp.Method = http.MethodPost 177 q := bckFrom.NewQuery() 178 _ = bckTo.AddUnameToQuery(q, apc.QparamBckTo) 179 if len(fltPresence) > 0 { 180 q.Set(apc.QparamFltPresence, strconv.Itoa(fltPresence[0])) 181 } 182 reqParams := AllocRp() 183 { 184 reqParams.BaseParams = bp 185 reqParams.Path = apc.URLPathBuckets.Join(bckFrom.Name) 186 reqParams.Body = cos.MustMarshal(apc.ActMsg{Action: apc.ActETLBck, Value: msg}) 187 reqParams.Header = http.Header{cos.HdrContentType: []string{cos.ContentJSON}} 188 reqParams.Query = q 189 } 190 _, err = reqParams.doReqStr(&xid) 191 FreeRp(reqParams) 192 return 193 }