github.com/kubeshop/testkube@v1.17.23/pkg/storage/minio/minio.go (about) 1 package minio 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "hash/fnv" 8 "io" 9 "os" 10 "path/filepath" 11 "regexp" 12 "strings" 13 "time" 14 15 "github.com/pkg/errors" 16 17 "github.com/minio/minio-go/v7" 18 "github.com/minio/minio-go/v7/pkg/lifecycle" 19 "go.uber.org/zap" 20 21 "github.com/kubeshop/testkube/pkg/api/v1/testkube" 22 "github.com/kubeshop/testkube/pkg/archive" 23 "github.com/kubeshop/testkube/pkg/executor/output" 24 "github.com/kubeshop/testkube/pkg/log" 25 "github.com/kubeshop/testkube/pkg/storage" 26 "github.com/kubeshop/testkube/pkg/ui" 27 ) 28 29 var _ storage.Client = (*Client)(nil) 30 31 // ErrArtifactsNotFound contains error for not existing artifacts 32 var ErrArtifactsNotFound = errors.New("Execution doesn't have any artifacts associated with it") 33 34 // Client for managing MinIO storage server 35 type Client struct { 36 region string 37 bucket string 38 minioClient *minio.Client 39 Log *zap.SugaredLogger 40 minioConnecter *Connecter 41 } 42 43 // NewClient returns new MinIO client 44 func NewClient(endpoint, accessKeyID, secretAccessKey, region, token, bucket string, opts ...Option) *Client { 45 c := &Client{ 46 minioConnecter: NewConnecter(endpoint, accessKeyID, secretAccessKey, region, token, bucket, log.DefaultLogger, opts...), 47 region: region, 48 bucket: bucket, 49 Log: log.DefaultLogger, 50 } 51 52 return c 53 } 54 55 // Connect connects to MinIO server 56 func (c *Client) Connect() error { 57 var err error 58 c.minioClient, err = c.minioConnecter.GetClient() 59 return err 60 } 61 62 func (c *Client) SetExpirationPolicy(expirationDays int) error { 63 if expirationDays != 0 && c.minioClient != nil { 64 lifecycleConfig := &lifecycle.Configuration{ 65 Rules: []lifecycle.Rule{ 66 { 67 ID: "expiration_policy", 68 Status: "Enabled", 69 Expiration: lifecycle.Expiration{ 70 Days: lifecycle.ExpirationDays(expirationDays), 71 }, 72 }, 73 }, 74 } 75 return c.minioClient.SetBucketLifecycle(context.TODO(), c.bucket, lifecycleConfig) 76 } 77 return nil 78 } 79 80 // CreateBucket creates new S3 like bucket 81 func (c *Client) CreateBucket(ctx context.Context, bucket string) error { 82 if err := c.Connect(); err != nil { 83 return err 84 } 85 err := c.minioClient.MakeBucket(ctx, bucket, minio.MakeBucketOptions{Region: c.region}) 86 if err != nil { 87 c.Log.Errorw("error creating bucket", "error", err) 88 // Check to see if we already own this bucket (which happens if you run this twice) 89 exists, errBucketExists := c.minioClient.BucketExists(ctx, bucket) 90 if errBucketExists == nil && exists { 91 return fmt.Errorf("bucket %q already exists", bucket) 92 } else { 93 return err 94 } 95 } 96 return nil 97 } 98 99 // DeleteBucket deletes bucket by name 100 func (c *Client) DeleteBucket(ctx context.Context, bucket string, force bool) error { 101 if err := c.Connect(); err != nil { 102 return err 103 } 104 return c.minioClient.RemoveBucketWithOptions(ctx, bucket, minio.RemoveBucketOptions{ForceDelete: force}) 105 } 106 107 // ListBuckets lists available buckets 108 func (c *Client) ListBuckets(ctx context.Context) ([]string, error) { 109 if err := c.Connect(); err != nil { 110 return nil, err 111 } 112 var toReturn []string 113 if buckets, err := c.minioClient.ListBuckets(ctx); err != nil { 114 return nil, err 115 } else { 116 for _, bucket := range buckets { 117 toReturn = append(toReturn, bucket.Name) 118 } 119 } 120 return toReturn, nil 121 } 122 123 // listFiles lists available files in given bucket 124 func (c *Client) listFiles(ctx context.Context, bucket, bucketFolder string) ([]testkube.Artifact, error) { 125 if err := c.Connect(); err != nil { 126 return nil, err 127 } 128 var toReturn []testkube.Artifact 129 130 exists, err := c.minioClient.BucketExists(ctx, bucket) 131 if err != nil { 132 return nil, err 133 } 134 135 if !exists { 136 c.Log.Debugw("bucket doesn't exist", "bucket", bucket) 137 return nil, ErrArtifactsNotFound 138 } 139 listOptions := minio.ListObjectsOptions{Recursive: true} 140 if bucketFolder != "" { 141 listOptions.Prefix = bucketFolder 142 } 143 144 for obj := range c.minioClient.ListObjects(ctx, bucket, listOptions) { 145 if obj.Err != nil { 146 return nil, obj.Err 147 } 148 if bucketFolder != "" { 149 obj.Key = strings.TrimPrefix(obj.Key, bucketFolder+"/") 150 } 151 toReturn = append(toReturn, testkube.Artifact{Name: obj.Key, Size: int32(obj.Size)}) 152 } 153 154 return toReturn, nil 155 } 156 157 // ListFiles lists available files in the bucket from the config 158 func (c *Client) ListFiles(ctx context.Context, bucketFolder string) ([]testkube.Artifact, error) { 159 c.Log.Infow("listing files", "bucket", c.bucket, "bucketFolder", bucketFolder) 160 // TODO: this is for back compatibility, remove it sometime in the future 161 if bucketFolder != "" { 162 if exist, err := c.minioClient.BucketExists(ctx, bucketFolder); err == nil && exist { 163 formerResult, err := c.listFiles(ctx, bucketFolder, "") 164 if err == nil && len(formerResult) > 0 { 165 return formerResult, nil 166 } 167 } 168 } 169 170 return c.listFiles(ctx, c.bucket, bucketFolder) 171 } 172 173 // saveFile saves file defined by local filePath to S3 bucket 174 func (c *Client) saveFile(ctx context.Context, bucket, bucketFolder, filePath string) error { 175 c.Log.Debugw("saving file", "bucket", bucket, "bucketFolder", bucketFolder, "filePath", filePath) 176 if err := c.Connect(); err != nil { 177 return err 178 } 179 object, err := os.Open(filePath) 180 if err != nil { 181 return fmt.Errorf("minio saving file (%s) open error: %w", filePath, err) 182 } 183 defer object.Close() 184 objectStat, err := object.Stat() 185 if err != nil { 186 return fmt.Errorf("minio object stat (file:%s) error: %w", filePath, err) 187 } 188 189 exists, err := c.minioClient.BucketExists(ctx, bucket) 190 if err != nil || !exists { 191 err := c.CreateBucket(ctx, bucket) 192 if err != nil { 193 return fmt.Errorf("minio saving file (%s) bucket was not created and create bucket returnes error: %w", filePath, err) 194 } 195 } 196 197 fileName := objectStat.Name() 198 if bucketFolder != "" { 199 fileName = strings.Trim(bucketFolder, "/") + "/" + fileName 200 } 201 202 c.Log.Debugw("saving object in minio", "filePath", filePath, "fileName", fileName, "bucket", bucket, "size", objectStat.Size()) 203 _, err = c.minioClient.PutObject(ctx, bucket, fileName, object, objectStat.Size(), minio.PutObjectOptions{ContentType: "application/octet-stream"}) 204 if err != nil { 205 return fmt.Errorf("minio saving file (%s) put object error: %w", fileName, err) 206 } 207 208 return nil 209 } 210 211 func (c *Client) SaveFileDirect(ctx context.Context, folder, file string, data io.Reader, size int64, opts minio.PutObjectOptions) error { 212 exists, err := c.minioClient.BucketExists(ctx, c.bucket) 213 if err != nil { 214 return errors.Wrapf(err, "error checking does bucket %s exists", c.bucket) 215 } 216 if !exists { 217 if err := c.CreateBucket(ctx, c.bucket); err != nil { 218 return errors.Wrapf(err, "error creating bucket %s", c.bucket) 219 } 220 } 221 222 filename := file 223 if folder != "" { 224 filename = fmt.Sprintf("%s/%s", folder, filename) 225 } 226 227 if opts.ContentType == "" { 228 opts.ContentType = "application/octet-stream" 229 } 230 c.Log.Debugw("saving object in minio", "filename", filename, "bucket", c.bucket, "size", size) 231 _, err = c.minioClient.PutObject(ctx, c.bucket, filename, data, size, opts) 232 if err != nil { 233 return errors.Wrapf(err, "minio saving file (%s) put object error", filename) 234 } 235 236 return nil 237 } 238 239 // SaveFile saves file defined by local filePath to S3 bucket from the config 240 func (c *Client) SaveFile(ctx context.Context, bucketFolder, filePath string) error { 241 c.Log.Debugw("SaveFile", "bucket", c.bucket, "bucketFolder", bucketFolder, "filePath", filePath) 242 return c.saveFile(ctx, c.bucket, bucketFolder, filePath) 243 } 244 245 // downloadFile downloads file from bucket 246 func (c *Client) downloadFile(ctx context.Context, bucket, bucketFolder, file string) (*minio.Object, error) { 247 c.Log.Debugw("downloadFile", "bucket", bucket, "bucketFolder", bucketFolder, "file", file) 248 if err := c.Connect(); err != nil { 249 return nil, fmt.Errorf("minio DownloadFile .Connect error: %w", err) 250 } 251 252 exists, err := c.minioClient.BucketExists(ctx, bucket) 253 if err != nil { 254 return nil, err 255 } 256 257 if !exists { 258 c.Log.Infow("bucket doesn't exist", "bucket", bucket) 259 return nil, ErrArtifactsNotFound 260 } 261 262 if bucketFolder != "" { 263 file = strings.Trim(bucketFolder, "/") + "/" + file 264 } 265 266 reader, err := c.minioClient.GetObject(ctx, bucket, file, minio.GetObjectOptions{}) 267 if err != nil { 268 return nil, fmt.Errorf("minio DownloadFile GetObject error: %w", err) 269 } 270 271 _, err = reader.Stat() 272 if err != nil { 273 return reader, fmt.Errorf("minio Download File Stat error: %w", err) 274 } 275 276 return reader, nil 277 } 278 279 // DownloadFile downloads file from bucket from the config 280 func (c *Client) DownloadFile(ctx context.Context, bucketFolder, file string) (*minio.Object, error) { 281 c.Log.Infow("Download file", "bucket", c.bucket, "bucketFolder", bucketFolder, "file", file) 282 // TODO: this is for back compatibility, remove it sometime in the future 283 var objFirst *minio.Object 284 var errFirst error 285 if bucketFolder != "" { 286 exists, err := c.minioClient.BucketExists(ctx, bucketFolder) 287 c.Log.Debugw("Checking if bucket exists", exists, err) 288 if err == nil && exists { 289 c.Log.Infow("Bucket exists, trying to get files from former bucket per execution", exists, err) 290 objFirst, errFirst = c.downloadFile(ctx, bucketFolder, "", file) 291 if errFirst == nil && objFirst != nil { 292 return objFirst, nil 293 } 294 } 295 } 296 objSecond, errSecond := c.downloadFile(ctx, c.bucket, bucketFolder, file) 297 if errSecond != nil { 298 return nil, fmt.Errorf("minio DownloadFile error: %v, error from getting files from former bucket per execution: %v", errSecond, errFirst) 299 } 300 return objSecond, nil 301 } 302 303 // downloadArchive downloads archive from bucket 304 func (c *Client) downloadArchive(ctx context.Context, bucket, bucketFolder string, masks []string) (io.Reader, error) { 305 c.Log.Debugw("downloadArchive", "bucket", bucket, "bucketFolder", bucketFolder, "masks", masks) 306 if err := c.Connect(); err != nil { 307 return nil, fmt.Errorf("minio DownloadArchive .Connect error: %w", err) 308 } 309 310 exists, err := c.minioClient.BucketExists(ctx, bucket) 311 if err != nil { 312 return nil, err 313 } 314 315 if !exists { 316 c.Log.Infow("bucket doesn't exist", "bucket", bucket) 317 return nil, ErrArtifactsNotFound 318 } 319 320 var regexps []*regexp.Regexp 321 for _, mask := range masks { 322 values := strings.Split(mask, ",") 323 for _, value := range values { 324 re, err := regexp.Compile(value) 325 if err != nil { 326 return nil, fmt.Errorf("minio DownloadArchive regexp error: %w", err) 327 } 328 329 regexps = append(regexps, re) 330 } 331 } 332 333 listOptions := minio.ListObjectsOptions{Recursive: true} 334 if bucketFolder != "" { 335 listOptions.Prefix = strings.Trim(bucketFolder, "/") 336 } 337 338 var files []*archive.File 339 for obj := range c.minioClient.ListObjects(ctx, bucket, listOptions) { 340 if obj.Err != nil { 341 return nil, fmt.Errorf("minio DownloadArchive ListObjects error: %w", obj.Err) 342 } 343 344 found := len(regexps) == 0 345 for i := range regexps { 346 if found = regexps[i].MatchString(obj.Key); found { 347 break 348 } 349 } 350 351 if !found { 352 continue 353 } 354 355 files = append(files, &archive.File{ 356 Name: obj.Key, 357 Size: obj.Size, 358 Mode: int64(os.ModePerm), 359 ModTime: obj.LastModified, 360 }) 361 } 362 363 for i := range files { 364 reader, err := c.minioClient.GetObject(ctx, bucket, files[i].Name, minio.GetObjectOptions{}) 365 if err != nil { 366 return nil, fmt.Errorf("minio DownloadArchive GetObject error: %w", err) 367 } 368 369 if _, err = reader.Stat(); err != nil { 370 return nil, fmt.Errorf("minio DownloadArchive Stat error: %w", err) 371 } 372 373 files[i].Data = &bytes.Buffer{} 374 if _, err = files[i].Data.ReadFrom(reader); err != nil { 375 return nil, fmt.Errorf("minio DownloadArchive Read error: %w", err) 376 } 377 } 378 379 service := archive.NewTarballService() 380 data := &bytes.Buffer{} 381 if err = service.Create(data, files); err != nil { 382 return nil, fmt.Errorf("minio DownloadArchive CreateArchive error: %w", err) 383 } 384 385 return data, nil 386 } 387 388 // DownloadArchive downloads archive from bucket from the config 389 func (c *Client) DownloadArchive(ctx context.Context, bucketFolder string, masks []string) (io.Reader, error) { 390 c.Log.Infow("Download archive", "bucket", c.bucket, "bucketFolder", bucketFolder, "masks", masks) 391 // TODO: this is for back compatibility, remove it sometime in the future 392 var objFirst io.Reader 393 var errFirst error 394 if bucketFolder != "" { 395 exists, err := c.minioClient.BucketExists(ctx, bucketFolder) 396 c.Log.Debugw("Checking if bucket exists", exists, err) 397 if err == nil && exists { 398 c.Log.Infow("Bucket exists, trying to get archive from former bucket per execution", exists, err) 399 objFirst, errFirst = c.downloadArchive(ctx, bucketFolder, "", masks) 400 if errFirst == nil && objFirst != nil { 401 return objFirst, nil 402 } 403 } 404 } 405 objSecond, errSecond := c.downloadArchive(ctx, c.bucket, bucketFolder, masks) 406 if errSecond != nil { 407 return nil, fmt.Errorf("minio DownloadArchive error: %v, error from getting archive from former bucket per execution: %v", errSecond, errFirst) 408 } 409 return objSecond, nil 410 } 411 412 // DownloadFileFromBucket downloads file from given bucket 413 func (c *Client) DownloadFileFromBucket(ctx context.Context, bucket, bucketFolder, file string) (io.Reader, minio.ObjectInfo, error) { 414 c.Log.Debugw("Downloading file", "bucket", bucket, "bucketFolder", bucketFolder, "file", file) 415 object, err := c.downloadFile(ctx, bucket, bucketFolder, file) 416 if err != nil { 417 return nil, minio.ObjectInfo{}, err 418 } 419 420 info, err := object.Stat() 421 if err != nil { 422 return nil, minio.ObjectInfo{}, err 423 } 424 425 return object, info, nil 426 } 427 428 // DownloadArrchiveFromBucket downloads archive from given bucket 429 func (c *Client) DownloadArchiveFromBucket(ctx context.Context, bucket, bucketFolder string, masks []string) (io.Reader, error) { 430 c.Log.Debugw("Downloading archive", "bucket", bucket, "bucketFolder", bucketFolder, "masks", masks) 431 return c.downloadArchive(ctx, bucket, bucketFolder, masks) 432 } 433 434 // ScrapeArtefacts pushes local files located in directories to given folder with given id located in the configured bucket 435 func (c *Client) ScrapeArtefacts(ctx context.Context, id string, directories ...string) error { 436 if err := c.Connect(); err != nil { 437 return fmt.Errorf("minio scrape artefacts connection error: %w", err) 438 } 439 440 for _, directory := range directories { 441 442 if _, err := os.Stat(directory); os.IsNotExist(err) { 443 c.Log.Debugw("directory %s does not exist, skipping", directory) 444 continue 445 } 446 447 // if directory exists walk through recursively 448 err := filepath.Walk(directory, 449 func(path string, info os.FileInfo, err error) error { 450 if err != nil { 451 return fmt.Errorf("minio path (%s) walk error: %w", path, err) 452 } 453 454 if !info.IsDir() { 455 err = c.SaveFile(ctx, id, path) //The function will detect if there is a subdirectory and store accordingly 456 if err != nil { 457 return fmt.Errorf("minio save file (%s) error: %w", path, err) 458 } 459 } 460 return nil 461 }) 462 463 if err != nil { 464 return fmt.Errorf("minio walk error: %w", err) 465 } 466 } 467 return nil 468 } 469 470 // uploadFile saves a file to be copied into a running execution 471 func (c *Client) uploadFile(ctx context.Context, bucket, bucketFolder, filePath string, reader io.Reader, objectSize int64) error { 472 if err := c.Connect(); err != nil { 473 return fmt.Errorf("minio UploadFile connection error: %w", err) 474 } 475 476 exists, err := c.minioClient.BucketExists(ctx, bucket) 477 if err != nil { 478 return fmt.Errorf("could not check if bucket already exists for copy files: %w", err) 479 } 480 481 if !exists { 482 c.Log.Debugw("creating minio bucket for copy files", "bucket", bucket) 483 err := c.CreateBucket(ctx, bucket) 484 if err != nil { 485 return fmt.Errorf("could not create bucket: %w", err) 486 } 487 } 488 489 if bucketFolder != "" { 490 filePath = strings.Trim(bucketFolder, "/") + "/" + filePath 491 } 492 493 c.Log.Debugw("saving object in minio", "file", filePath, "bucket", bucket) 494 _, err = c.minioClient.PutObject(ctx, bucket, filePath, reader, objectSize, minio.PutObjectOptions{ContentType: "application/octet-stream"}) 495 if err != nil { 496 return fmt.Errorf("minio saving file (%s) put object error: %w", filePath, err) 497 } 498 499 return nil 500 } 501 502 // UploadFile saves a file to be copied into a running execution 503 func (c *Client) UploadFile(ctx context.Context, bucketFolder, filePath string, reader io.Reader, objectSize int64) error { 504 return c.uploadFile(ctx, c.bucket, bucketFolder, filePath, reader, objectSize) 505 } 506 507 // UploadFileToBucket saves a file to be copied into a running execution 508 func (c *Client) UploadFileToBucket(ctx context.Context, bucket, bucketFolder, filePath string, reader io.Reader, objectSize int64) error { 509 return c.uploadFile(ctx, bucket, bucketFolder, filePath, reader, objectSize) 510 } 511 512 // PlaceFiles saves the content of the buckets to the filesystem 513 func (c *Client) PlaceFiles(ctx context.Context, bucketFolders []string, prefix string) error { 514 output.PrintLog(fmt.Sprintf("%s Getting the contents of bucket folders %s", ui.IconFile, bucketFolders)) 515 if err := c.Connect(); err != nil { 516 output.PrintLog(fmt.Sprintf("%s Minio PlaceFiles connection error: %s", ui.IconWarning, err.Error())) 517 return fmt.Errorf("minio PlaceFiles connection error: %w", err) 518 } 519 exists, err := c.minioClient.BucketExists(ctx, c.bucket) 520 if err != nil { 521 output.PrintLog(fmt.Sprintf("%s Could not check if bucket already exists for files %s", ui.IconWarning, err.Error())) 522 return fmt.Errorf("could not check if bucket already exists for files: %w", err) 523 } 524 if !exists { 525 output.PrintLog(fmt.Sprintf("%s Bucket %s does not exist", ui.IconFile, c.bucket)) 526 return fmt.Errorf("bucket %s does not exist", c.bucket) 527 } 528 for _, folder := range bucketFolders { 529 530 files, err := c.ListFiles(ctx, folder) 531 if err != nil { 532 output.PrintLog(fmt.Sprintf("%s Could not list files in bucket %s folder %s", ui.IconWarning, c.bucket, folder)) 533 return fmt.Errorf("could not list files in bucket %s folder %s", c.bucket, folder) 534 } 535 536 for _, f := range files { 537 output.PrintEvent(fmt.Sprintf("%s Downloading file %s", ui.IconFile, f.Name)) 538 c.Log.Infof("Getting file %s", f) 539 objectName := f.Name 540 541 isFileDownloadable := strings.TrimSpace(objectName) != "" && !strings.HasSuffix(objectName, "/") 542 if !isFileDownloadable { 543 output.PrintEvent(fmt.Sprintf("%s File %s cannot be downloaded", ui.IconCross, objectName)) 544 continue 545 } 546 547 if folder != "" { 548 objectName = fmt.Sprintf("%s/%s", folder, objectName) 549 } 550 551 path := filepath.Join(prefix, f.Name) 552 err = c.minioClient.FGetObject(ctx, c.bucket, objectName, path, minio.GetObjectOptions{}) 553 if err != nil { 554 output.PrintEvent(fmt.Sprintf("%s Could not download file %s", ui.IconCross, f.Name)) 555 return fmt.Errorf("could not persist file %s from bucket %s, folder %s: %w", f.Name, c.bucket, folder, err) 556 } 557 output.PrintEvent(fmt.Sprintf("%s File %s successfully downloaded into %s", ui.IconCheckMark, f.Name, prefix)) 558 } 559 } 560 return nil 561 } 562 563 // GetValidBucketName returns a minio-compatible bucket name 564 func (c *Client) GetValidBucketName(parentType string, parentName string) string { 565 bucketName := fmt.Sprintf("%s-%s", parentType, parentName) 566 if len(bucketName) <= 63 { 567 return bucketName 568 } 569 570 h := fnv.New32a() 571 h.Write([]byte(bucketName)) 572 573 return fmt.Sprintf("%s-%d", bucketName[:52], h.Sum32()) 574 } 575 576 func (c *Client) deleteFile(ctx context.Context, bucket, bucketFolder, file string) error { 577 if err := c.Connect(); err != nil { 578 return fmt.Errorf("minio DeleteFile connection error: %w", err) 579 } 580 581 exists, err := c.minioClient.BucketExists(ctx, bucket) 582 if err != nil { 583 return fmt.Errorf("could not check if bucket already exists for delete file: %w", err) 584 } 585 586 if !exists { 587 c.Log.Warnf("bucket %s does not exist", bucket) 588 return ErrArtifactsNotFound 589 } 590 591 if bucketFolder != "" { 592 file = strings.Trim(bucketFolder, "/") + "/" + file 593 } 594 595 err = c.minioClient.RemoveObject(ctx, bucket, file, minio.RemoveObjectOptions{ForceDelete: true}) 596 if err != nil { 597 return fmt.Errorf("minio DeleteFile RemoveObject error: %w", err) 598 } 599 600 return nil 601 } 602 603 // DeleteFile deletes a file from a bucket folder where bucket is provided by config 604 func (c *Client) DeleteFile(ctx context.Context, bucketFolder, file string) error { 605 // TODO: this is for back compatibility, remove it sometime in the future 606 var errFirst error 607 if bucketFolder != "" { 608 if exist, err := c.minioClient.BucketExists(ctx, bucketFolder); err != nil || !exist { 609 errFirst = c.DeleteFileFromBucket(ctx, bucketFolder, "", file) 610 if err == nil { 611 return nil 612 } 613 614 } 615 } 616 errSecond := c.deleteFile(ctx, c.bucket, bucketFolder, file) 617 if errFirst != nil { 618 return fmt.Errorf("deleting file error: %v, previous attemt to delete file from one bucket per execution error: %v", errSecond, errFirst) 619 } 620 return errSecond 621 } 622 623 // DeleteFileFromBucket deletes a file from a bucket folder 624 func (c *Client) DeleteFileFromBucket(ctx context.Context, bucket, bucketFolder, file string) error { 625 return c.deleteFile(ctx, bucket, bucketFolder, file) 626 } 627 628 // IsConnectionPossible checks if the connection to minio is possible 629 func (c *Client) IsConnectionPossible(ctx context.Context) (bool, error) { 630 if err := c.Connect(); err != nil { 631 return false, err 632 } 633 634 return true, nil 635 } 636 637 func (c *Client) PresignDownloadFileFromBucket(ctx context.Context, bucket, bucketFolder, file string, expires time.Duration) (string, error) { 638 if err := c.Connect(); err != nil { 639 return "", err 640 } 641 if bucketFolder != "" { 642 file = strings.Trim(bucketFolder, "/") + "/" + file 643 } 644 c.Log.Debugw("presigning get object from minio", "file", file, "bucket", bucket) 645 url, err := c.minioClient.PresignedPutObject(ctx, bucket, file, expires) 646 if err != nil { 647 return "", err 648 } 649 return url.String(), nil 650 } 651 652 func (c *Client) PresignUploadFileToBucket(ctx context.Context, bucket, bucketFolder, filePath string, expires time.Duration) (string, error) { 653 if err := c.Connect(); err != nil { 654 return "", err 655 } 656 if bucketFolder != "" { 657 filePath = strings.Trim(bucketFolder, "/") + "/" + filePath 658 } 659 c.Log.Debugw("presigning put object in minio", "file", filePath, "bucket", bucket) 660 url, err := c.minioClient.PresignedPutObject(ctx, bucket, filePath, expires) 661 if err != nil { 662 return "", err 663 } 664 return url.String(), nil 665 }