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 }