github.com/matrixorigin/matrixone@v1.2.0/pkg/fileservice/get.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://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,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fileservice
    16  
    17  import (
    18  	"context"
    19  	"os"
    20  	"path/filepath"
    21  	"strings"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    24  )
    25  
    26  func Get[T any](fs FileService, name string) (res T, err error) {
    27  	lowerName := strings.ToLower(name)
    28  	if fs, ok := fs.(*FileServices); ok {
    29  		f, ok := fs.mappings[lowerName]
    30  		if !ok {
    31  			err = moerr.NewNoServiceNoCtx(name)
    32  			return
    33  		}
    34  		res, ok = f.(T)
    35  		if !ok {
    36  			err = moerr.NewNoServiceNoCtx(name)
    37  			return
    38  		}
    39  		return
    40  	}
    41  	var ok bool
    42  	res, ok = fs.(T)
    43  	if !ok {
    44  		err = moerr.NewNoServiceNoCtx(name)
    45  		return
    46  	}
    47  	if !strings.EqualFold(fs.Name(), lowerName) {
    48  		err = moerr.NewNoServiceNoCtx(name)
    49  		return
    50  	}
    51  	return
    52  }
    53  
    54  var NoDefaultCredentialsForETL = os.Getenv("MO_NO_DEFAULT_CREDENTIALS") != ""
    55  
    56  // GetForETL get or creates a FileService instance for ETL operations
    57  // if service part of path is empty, a LocalETLFS will be created
    58  // if service part of path is not empty, a ETLFileService typed instance will be extracted from fs argument
    59  // if service part of path is argumented, a FileService instance will be created dynamically with those arguments
    60  // supported dynamic file service:
    61  // s3,<endpoint>,<region>,<bucket>,<key>,<secret>,<prefix>
    62  // s3-no-key,<endpoint>,<region>,<bucket>,<prefix>
    63  // minio,<endpoint>,<region>,<bucket>,<key>,<secret>,<prefix>
    64  // s3-opts,endpoint=<endpoint>,region=<region>,bucket=<bucket>,key=<key>,secret=<secret>,prefix=<prefix>,role-arn=<role arn>,external-id=<external id>
    65  //
    66  //	key value pairs can be in any order
    67  func GetForETL(ctx context.Context, fs FileService, path string) (res ETLFileService, readPath string, err error) {
    68  	fsPath, err := ParsePath(path)
    69  	if err != nil {
    70  		return nil, "", err
    71  	}
    72  
    73  	if fsPath.Service == "" {
    74  		// no service, create local ETL fs
    75  		dir, file := filepath.Split(path)
    76  		res, err = NewLocalETLFS("etl", dir)
    77  		if err != nil {
    78  			return nil, "", err
    79  		}
    80  		readPath = file
    81  
    82  	} else if len(fsPath.ServiceArguments) > 0 {
    83  		// service with arguments, create dynamically
    84  		switch fsPath.Service {
    85  
    86  		case "s3":
    87  			arguments := fsPath.ServiceArguments
    88  			if len(arguments) < 6 {
    89  				return nil, "", moerr.NewInvalidInputNoCtx("invalid S3 arguments")
    90  			}
    91  			endpoint := arguments[0]
    92  			region := arguments[1]
    93  			bucket := arguments[2]
    94  			accessKey := arguments[3]
    95  			accessSecret := arguments[4]
    96  			keyPrefix := arguments[5]
    97  			var name string
    98  			if len(arguments) > 6 {
    99  				name = arguments[6]
   100  			}
   101  
   102  			res, err = NewS3FS(
   103  				ctx,
   104  				ObjectStorageArguments{
   105  					NoBucketValidation: true,
   106  					Endpoint:           endpoint,
   107  					Region:             region,
   108  					Bucket:             bucket,
   109  					KeyID:              accessKey,
   110  					KeySecret:          accessSecret,
   111  					KeyPrefix:          keyPrefix,
   112  					Name:               name,
   113  				},
   114  				DisabledCacheConfig,
   115  				nil,
   116  				true,
   117  				NoDefaultCredentialsForETL,
   118  			)
   119  			if err != nil {
   120  				return
   121  			}
   122  
   123  		case "s3-no-key":
   124  			arguments := fsPath.ServiceArguments
   125  			if len(arguments) < 4 {
   126  				return nil, "", moerr.NewInvalidInputNoCtx("invalid S3 arguments")
   127  			}
   128  			endpoint := arguments[0]
   129  			region := arguments[1]
   130  			bucket := arguments[2]
   131  			keyPrefix := arguments[3]
   132  			var name string
   133  			if len(arguments) > 4 {
   134  				name = arguments[4]
   135  			}
   136  
   137  			res, err = NewS3FS(
   138  				ctx,
   139  				ObjectStorageArguments{
   140  					NoBucketValidation: true,
   141  					Endpoint:           endpoint,
   142  					Region:             region,
   143  					Bucket:             bucket,
   144  					KeyPrefix:          keyPrefix,
   145  					Name:               name,
   146  				},
   147  				DisabledCacheConfig,
   148  				nil,
   149  				true,
   150  				NoDefaultCredentialsForETL,
   151  			)
   152  
   153  		case "s3-opts":
   154  			var args ObjectStorageArguments
   155  			if err := args.SetFromString(fsPath.ServiceArguments); err != nil {
   156  				return nil, "", err
   157  			}
   158  			args.NoBucketValidation = true
   159  			res, err = NewS3FS(
   160  				ctx,
   161  				args,
   162  				DisabledCacheConfig,
   163  				nil,
   164  				true,
   165  				NoDefaultCredentialsForETL,
   166  			)
   167  			if err != nil {
   168  				return
   169  			}
   170  
   171  		case "minio":
   172  			arguments := fsPath.ServiceArguments
   173  			if len(arguments) < 6 {
   174  				return nil, "", moerr.NewInvalidInputNoCtx("invalid S3 arguments")
   175  			}
   176  			endpoint := arguments[0]
   177  			region := arguments[1]
   178  			_ = region
   179  			bucket := arguments[2]
   180  			accessKey := arguments[3]
   181  			accessSecret := arguments[4]
   182  			keyPrefix := arguments[5]
   183  			var name string
   184  			if len(arguments) > 6 {
   185  				name = arguments[6]
   186  			}
   187  
   188  			res, err = NewS3FS(
   189  				ctx,
   190  				ObjectStorageArguments{
   191  					NoBucketValidation: true,
   192  					Endpoint:           endpoint,
   193  					Region:             region,
   194  					Bucket:             bucket,
   195  					KeyID:              accessKey,
   196  					KeySecret:          accessSecret,
   197  					KeyPrefix:          keyPrefix,
   198  					Name:               name,
   199  					IsMinio:            true,
   200  				},
   201  				DisabledCacheConfig,
   202  				nil,
   203  				true,
   204  				NoDefaultCredentialsForETL,
   205  			)
   206  			if err != nil {
   207  				return
   208  			}
   209  
   210  		default:
   211  			err = moerr.NewInvalidInputNoCtx("no such service: %s", fsPath.Service)
   212  		}
   213  
   214  		readPath = fsPath.File
   215  
   216  	} else {
   217  		// get etl fs
   218  		res, err = Get[ETLFileService](fs, fsPath.Service)
   219  		if err != nil {
   220  			return nil, "", err
   221  		}
   222  		readPath = path
   223  	}
   224  
   225  	return
   226  }
   227  
   228  // GetForBackup creates a FileService instance for backup operations
   229  // if service part of path is empty, a LocalFS will be created
   230  // if service part of path is argumented, a FileService instance will be created dynamically with those arguments
   231  // supported dynamic file service:
   232  // s3-opts,endpoint=<endpoint>,region=<region>,bucket=<bucket>,key=<key>,secret=<secret>,prefix=<prefix>,role-arn=<role arn>,external-id=<external id>,is-minio=<is-minio>
   233  func GetForBackup(ctx context.Context, spec string) (res FileService, err error) {
   234  	fsPath, err := ParsePath(spec)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	if fsPath.Service == "" {
   240  		// no service, create local fs
   241  		res, err = NewLocalFS(context.Background(), "backup", spec, DisabledCacheConfig, nil)
   242  		if err != nil {
   243  			return nil, err
   244  		}
   245  
   246  	} else if len(fsPath.ServiceArguments) > 0 {
   247  		// service with arguments, create dynamically
   248  		switch fsPath.Service {
   249  
   250  		case "s3-opts":
   251  			var args ObjectStorageArguments
   252  			if err := args.SetFromString(fsPath.ServiceArguments); err != nil {
   253  				return nil, err
   254  			}
   255  			args.NoBucketValidation = true
   256  			res, err = NewS3FS(
   257  				ctx,
   258  				args,
   259  				DisabledCacheConfig,
   260  				nil,
   261  				true,
   262  				false,
   263  			)
   264  			if err != nil {
   265  				return
   266  			}
   267  
   268  		default:
   269  			err = moerr.NewInvalidInputNoCtx("no such service: %s", fsPath.Service)
   270  		}
   271  
   272  	} else {
   273  		return nil, moerr.NewInvalidInputNoCtx("unknown file service: %v", spec)
   274  	}
   275  
   276  	return
   277  }