package storage import ( "github.com/minio/minio-go/v6" "bpa-restapi-agent/internal/config" "log" "os" ) type MinIOInfo struct { minioC *minio.Client `json:"minio client"` } // Initialize the MinIO server, create buckets func Initialize() (MinIOInfo, error) { endpoint := config.GetConfiguration().MinIOAddress + ":" + config.GetConfiguration().MinIOPort accessKeyID := config.GetConfiguration().AccessKeyID secretAccessKey := config.GetConfiguration().SecretAccessKey useSSL := false minioInfo := MinIOInfo{} // Initialize minio client object. minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) if err != nil { log.Fatalln(err) return minioInfo, err } // Make a new bucket. bucketNames := []string{"binary", "container", "operatingsystem"} location := "us-west-1" for _, bucketName := range bucketNames { err := minioClient.MakeBucket(bucketName, location) if err != nil { // Check to see if we already own this bucket (which happens if you run this twice) exists, errBucketExists := minioClient.BucketExists(bucketName) if errBucketExists == nil && exists { log.Printf("We already own %s\n", bucketName) } else { log.Fatalln(err) return minioInfo, err } } else { log.Printf("Successfully created %s\n", bucketName) } } minioInfo.minioC = minioClient return minioInfo, nil } func (m MinIOInfo) PutImage(bucketName string, objName string, localPath string) (int64, error) { //contentType := "multipart/form-data" contentType := "application/octet-stream" // Upload the zip file with FPutObject n, err := m.minioC.FPutObject(bucketName, objName, localPath, minio.PutObjectOptions{ContentType:contentType}) if err != nil { log.Fatalln(err) return n, err } fileInfo, _ := os.Stat(localPath) fileSize := fileInfo.Size() if n != int64(fileSize) { log.Printf("FPutObject failed %s of size %d\n", objName, n) return n, err } log.Printf("Successfully uploaded %s of size %d\n", objName, n) return n, nil } func (m MinIOInfo) PatchImage(bucketName string, objName string, localPath string, offset int64, objSize int64) (int64, error) { var n = int64(0) tempFile, err := os.Open(localPath) if err != nil { log.Fatalln(err) return n, err } defer tempFile.Close() if _, err := tempFile.Seek(offset, 0); err != nil { log.Printf("PatchImage seek %s failed: %s", tempFile.Name(), err) return n, err } objInfo, err := m.minioC.StatObject(bucketName, objName, minio.StatObjectOptions{}) var objHealthy = true if err != nil { objHealthy = false } else if objInfo.Size != offset || objInfo.Size == 0 { objHealthy = false } var objNameTemp = objName if objHealthy { objNameTemp = objName + ".tmp" } contentType := "application/octet-stream" n, err = m.minioC.PutObject(bucketName, objNameTemp, tempFile, objSize, minio.PutObjectOptions{ContentType:contentType}) if err != nil { log.Fatalln(err) return n, err } if n != objSize { log.Printf("PatchImage PutObject %s failed with bytes: %d", tempFile.Name(), n) return n, err } if objHealthy { src1 := minio.NewSourceInfo(bucketName, objName, nil) src2 := minio.NewSourceInfo(bucketName, objNameTemp, nil) srcs := []minio.SourceInfo{src1, src2} dst, err := minio.NewDestinationInfo(bucketName, objName, nil, nil) if err != nil { log.Printf("NewDestinationInfo failed", err) return n, err } // There is issue, the last src should be the smallest obj size err = m.minioC.ComposeObject(dst, srcs) if err != nil { log.Printf("ComposeObject failed", err) return n, err } } log.Printf("Successfully PatchImage %s of size %d\n", objName, n) return n, nil } func (m MinIOInfo) DeleteImage(bucketName string, objName string) (error) { err := m.minioC.RemoveObject(bucketName, objName) if err != nil { log.Printf("MinIO Remove object %s failed\n", bucketName) return err } return nil } func (m MinIOInfo) CleanupImages(bucketName string) (error) { // create a done channel to control 'ListObjectsV2' go routine. doneCh := make(chan struct{}) defer close(doneCh) for objCh := range m.minioC.ListObjectsV2(bucketName, "", true, doneCh) { if objCh.Err != nil { return objCh.Err } if objCh.Key != "" { err := m.minioC.RemoveObject(bucketName, objCh.Key) if err != nil { return err } } } for objPartInfo := range m.minioC.ListIncompleteUploads(bucketName, "", true, doneCh) { if objPartInfo.Err != nil { return objPartInfo.Err } if objPartInfo.Key != "" { err := m.minioC.RemoveIncompleteUpload(bucketName, objPartInfo.Key) if err != nil { return err } } } return nil }