github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/veeam-sos-api.go (about)

     1  // Copyright (c) 2015-2023 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"bytes"
    22  	"context"
    23  	"encoding/xml"
    24  	"io"
    25  
    26  	"github.com/minio/madmin-go/v3"
    27  )
    28  
    29  // From Veeam-SOSAPI_1.0_Document_v1.02d.pdf
    30  // - SOSAPI Protocol Version
    31  // - Model Name of the vendor plus version for statistical analysis.
    32  // - List of Smart Object Storage protocol capabilities supported by the server.
    33  // Currently, there are three capabilities supported:
    34  //   - Capacity Reporting
    35  //   - Backup data locality for upload sessions (Veeam Smart Entity)
    36  //   - Handover of IAM & STS Endpoints instead of manual definition in Veeam Backup & Replication. This allows Veeam
    37  //     Agents to directly backup to object storage.
    38  //
    39  // An object storage system can implement one, multiple, or all functions.
    40  //
    41  //   - Optional (mandatory if <IAMSTS> is true): Set Endpoints for IAM and STS processing.
    42  //
    43  //   - Optional: Set server preferences for Backup & Replication parallel sessions, batch size of deletes, and block sizes (before
    44  //     compression). This is an optional area; by default, there should be no <SystemRecommendations> section in the
    45  //     system.xml. Vendors can work with Veeam Product Management and the Alliances team on getting approval to integrate
    46  //     specific system recommendations based on current support case statistics and storage performance possibilities.
    47  //     Vendors might change the settings based on the configuration and scale out of the solution (more storage nodes =>
    48  //     higher task limit).
    49  //
    50  //     <S3ConcurrentTaskLimit>
    51  //
    52  //   - Defines how many S3 operations are executed parallel within one Repository Task Slot (and within one backup object
    53  //     that gets offloaded). The same registry key setting overwrites the storage-defined setting.
    54  //     Optional value, default 64, range: 1-unlimited
    55  //
    56  //   - <S3MultiObjectDeleteLimit>
    57  //     Some of the Veeam products use Multi Delete operations. This setting can reduce how many objects are included in one
    58  //     multi-delete operation. The same registry key setting overwrites the storage-defined setting.
    59  //     Optional value, default 1000, range: 1-unlimited (S3 standard maximum is 1000 and should not be set higher)
    60  //
    61  //   - <StorageConcurrentTasksLimit>
    62  //     Setting reduces the parallel Repository Task slots that offload or write data to object storage. The same user interface
    63  //     setting overwrites the storage-defined setting.
    64  //     Optional value, default 0, range: 0-unlimited (0 equals unlimited, which means the maximum configured repository task
    65  //     slots are used for object offloading or writing)
    66  //
    67  //   - <KbBlockSize>
    68  //     Veeam Block Size for backup and restore processing before compression is applied. The higher the block size, the more
    69  //     backup space is needed for incremental backups. Larger block sizes also mean less performance for random read restore
    70  //     methods like Instant Restore, File Level Recovery, and Database/Application restores. Veeam recommends that vendors
    71  //     optimize the storage system for the default value of 1MB minus compression object sizes. The setting simultaneously
    72  //     affects read from source, block, file, dedup, and object storage backup targets for a specific Veeam Job. When customers
    73  //     create a new backup job and select the object storage or a SOBR as a backup target with this setting, the job default
    74  //     setting will be set to this value. This setting will be only applied to newly created jobs (manual changes with Active Full
    75  //     processing possible from the customer side).
    76  //     Optional value, default 1024, allowed values 256,512,1024,4096,8192, value defined in KB size.
    77  //
    78  // - The object should be present in all buckets accessed by Veeam products that want to leverage the SOSAPI functionality.
    79  //
    80  // - The current protocol version is 1.0.
    81  type apiEndpoints struct {
    82  	IAMEndpoint string `xml:"IAMEndpoint"`
    83  	STSEndpoint string `xml:"STSEndpoint"`
    84  }
    85  
    86  type systemInfo struct {
    87  	XMLName              xml.Name `xml:"SystemInfo" json:"-"`
    88  	ProtocolVersion      string   `xml:"ProtocolVersion"`
    89  	ModelName            string   `xml:"ModelName"`
    90  	ProtocolCapabilities struct {
    91  		CapacityInfo   bool `xml:"CapacityInfo"`
    92  		UploadSessions bool `xml:"UploadSessions"`
    93  		IAMSTS         bool `xml:"IAMSTS"`
    94  	} `mxl:"ProtocolCapabilities"`
    95  	APIEndpoints          *apiEndpoints `xml:"APIEndpoints,omitempty"`
    96  	SystemRecommendations struct {
    97  		S3ConcurrentTaskLimit    int `xml:"S3ConcurrentTaskLimit,omitempty"`
    98  		S3MultiObjectDeleteLimit int `xml:"S3MultiObjectDeleteLimit,omitempty"`
    99  		StorageCurrentTaskLimit  int `xml:"StorageCurrentTaskLimit,omitempty"`
   100  		KBBlockSize              int `xml:"KbBlockSize"`
   101  	} `xml:"SystemRecommendations"`
   102  }
   103  
   104  // This optional functionality allows vendors to report space information to Veeam products, and Veeam will make placement
   105  // decisions based on this information. For example, Veeam Backup & Replication has a Scale-out-Backup-Repository feature where
   106  // multiple buckets can be used together. The placement logic for additional backup files is based on available space. Other values
   107  // will augment the Veeam user interface and statistics, including free space warnings.
   108  type capacityInfo struct {
   109  	XMLName   xml.Name `xml:"CapacityInfo" json:"-"`
   110  	Capacity  int64    `xml:"Capacity"`
   111  	Available int64    `xml:"Available"`
   112  	Used      int64    `xml:"Used"`
   113  }
   114  
   115  const (
   116  	systemXMLObject   = ".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/system.xml"
   117  	capacityXMLObject = ".system-d26a9498-cb7c-4a87-a44a-8ae204f5ba6c/capacity.xml"
   118  )
   119  
   120  func isVeeamSOSAPIObject(object string) bool {
   121  	switch object {
   122  	case systemXMLObject, capacityXMLObject:
   123  		return true
   124  	default:
   125  		return false
   126  	}
   127  }
   128  
   129  func veeamSOSAPIHeadObject(ctx context.Context, bucket, object string, opts ObjectOptions) (ObjectInfo, error) {
   130  	gr, err := veeamSOSAPIGetObject(ctx, bucket, object, nil, opts)
   131  	if gr != nil {
   132  		gr.Close()
   133  		return gr.ObjInfo, nil
   134  	}
   135  	return ObjectInfo{}, err
   136  }
   137  
   138  func veeamSOSAPIGetObject(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, opts ObjectOptions) (gr *GetObjectReader, err error) {
   139  	var buf []byte
   140  	switch object {
   141  	case systemXMLObject:
   142  		si := systemInfo{
   143  			ProtocolVersion: `"1.0"`,
   144  			ModelName:       "\"MinIO " + ReleaseTag + "\"",
   145  		}
   146  		si.ProtocolCapabilities.CapacityInfo = true
   147  
   148  		// Default recommended block size with MinIO
   149  		si.SystemRecommendations.KBBlockSize = 4096
   150  
   151  		buf = encodeResponse(&si)
   152  	case capacityXMLObject:
   153  		objAPI := newObjectLayerFn()
   154  		if objAPI == nil {
   155  			return nil, errServerNotInitialized
   156  		}
   157  
   158  		q, _ := globalBucketQuotaSys.Get(ctx, bucket)
   159  		binfo, _ := globalBucketQuotaSys.GetBucketUsageInfo(bucket)
   160  
   161  		ci := capacityInfo{
   162  			Used: int64(binfo.Size),
   163  		}
   164  
   165  		var quotaSize int64
   166  		if q != nil && q.Type == madmin.HardQuota {
   167  			if q.Size > 0 {
   168  				quotaSize = int64(q.Size)
   169  			} else if q.Quota > 0 {
   170  				quotaSize = int64(q.Quota)
   171  			}
   172  		}
   173  
   174  		if quotaSize == 0 {
   175  			info := objAPI.StorageInfo(ctx, true)
   176  			info.Backend = objAPI.BackendInfo()
   177  
   178  			ci.Capacity = int64(GetTotalUsableCapacity(info.Disks, info))
   179  		} else {
   180  			ci.Capacity = quotaSize
   181  		}
   182  		ci.Available = ci.Capacity - ci.Used
   183  
   184  		buf = encodeResponse(&ci)
   185  	default:
   186  		return nil, errFileNotFound
   187  	}
   188  
   189  	etag := getMD5Hash(buf)
   190  	r := bytes.NewReader(buf)
   191  
   192  	off, length := int64(0), r.Size()
   193  	if rs != nil {
   194  		off, length, err = rs.GetOffsetLength(r.Size())
   195  		if err != nil {
   196  			return nil, err
   197  		}
   198  	}
   199  	r.Seek(off, io.SeekStart)
   200  
   201  	return NewGetObjectReaderFromReader(io.LimitReader(r, length), ObjectInfo{
   202  		Bucket:      bucket,
   203  		Name:        object,
   204  		Size:        r.Size(),
   205  		IsLatest:    true,
   206  		ContentType: string(mimeXML),
   207  		NumVersions: 1,
   208  		ETag:        etag,
   209  		ModTime:     UTCNow(),
   210  	}, opts)
   211  }