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  }