github.com/minio/madmin-go/v3@v3.0.51/tier.go (about)

     1  //
     2  // Copyright (c) 2015-2022 MinIO, Inc.
     3  //
     4  // This file is part of MinIO Object Storage stack
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU Affero General Public License as
     8  // published by the Free Software Foundation, either version 3 of the
     9  // License, or (at your option) any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU Affero General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU Affero General Public License
    17  // along with this program. If not, see <http://www.gnu.org/licenses/>.
    18  //
    19  
    20  package madmin
    21  
    22  import (
    23  	"context"
    24  	"encoding/json"
    25  	"io"
    26  	"net/http"
    27  	"net/url"
    28  	"path"
    29  	"strconv"
    30  	"time"
    31  )
    32  
    33  // tierAPI is API path prefix for tier related admin APIs
    34  const tierAPI = "tier"
    35  
    36  // AddTierIgnoreInUse adds a new remote tier, ignoring if it's being used by another MinIO deployment.
    37  func (adm *AdminClient) AddTierIgnoreInUse(ctx context.Context, cfg *TierConfig) error {
    38  	return adm.addTier(ctx, cfg, true)
    39  }
    40  
    41  // AddTier adds a new remote tier.
    42  func (adm *AdminClient) addTier(ctx context.Context, cfg *TierConfig, ignoreInUse bool) error {
    43  	data, err := json.Marshal(cfg)
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	encData, err := EncryptData(adm.getSecretKey(), data)
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	queryVals := url.Values{}
    54  	queryVals.Set("force", strconv.FormatBool(ignoreInUse))
    55  	reqData := requestData{
    56  		relPath:     path.Join(adminAPIPrefix, tierAPI),
    57  		content:     encData,
    58  		queryValues: queryVals,
    59  	}
    60  
    61  	// Execute PUT on /minio/admin/v3/tier to add a remote tier
    62  	resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
    63  	defer closeResponse(resp)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	if resp.StatusCode != http.StatusNoContent {
    69  		return httpRespToErrorResponse(resp)
    70  	}
    71  	return nil
    72  }
    73  
    74  // AddTier adds a new remote tier.
    75  func (adm *AdminClient) AddTier(ctx context.Context, cfg *TierConfig) error {
    76  	return adm.addTier(ctx, cfg, false)
    77  }
    78  
    79  // ListTiers returns a list of remote tiers configured.
    80  func (adm *AdminClient) ListTiers(ctx context.Context) ([]*TierConfig, error) {
    81  	reqData := requestData{
    82  		relPath: path.Join(adminAPIPrefix, tierAPI),
    83  	}
    84  
    85  	// Execute GET on /minio/admin/v3/tier to list remote tiers configured.
    86  	resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
    87  	defer closeResponse(resp)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	if resp.StatusCode != http.StatusOK {
    93  		return nil, httpRespToErrorResponse(resp)
    94  	}
    95  
    96  	var tiers []*TierConfig
    97  	b, err := io.ReadAll(resp.Body)
    98  	if err != nil {
    99  		return tiers, err
   100  	}
   101  
   102  	err = json.Unmarshal(b, &tiers)
   103  	if err != nil {
   104  		return tiers, err
   105  	}
   106  
   107  	return tiers, nil
   108  }
   109  
   110  // TierCreds is used to pass remote tier credentials in a tier-edit operation.
   111  type TierCreds struct {
   112  	AccessKey string `json:"access,omitempty"`
   113  	SecretKey string `json:"secret,omitempty"`
   114  
   115  	AWSRole                     bool   `json:"awsrole"`
   116  	AWSRoleWebIdentityTokenFile string `json:"awsroleWebIdentity,omitempty"`
   117  	AWSRoleARN                  string `json:"awsroleARN,omitempty"`
   118  
   119  	AzSP ServicePrincipalAuth `json:"azSP,omitempty"`
   120  
   121  	CredsJSON []byte `json:"creds,omitempty"`
   122  }
   123  
   124  // EditTier supports updating credentials for the remote tier identified by tierName.
   125  func (adm *AdminClient) EditTier(ctx context.Context, tierName string, creds TierCreds) error {
   126  	data, err := json.Marshal(creds)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	var encData []byte
   132  	encData, err = EncryptData(adm.getSecretKey(), data)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	reqData := requestData{
   138  		relPath: path.Join(adminAPIPrefix, tierAPI, tierName),
   139  		content: encData,
   140  	}
   141  
   142  	// Execute POST on /minio/admin/v3/tier/tierName to edit a tier
   143  	// configured.
   144  	resp, err := adm.executeMethod(ctx, http.MethodPost, reqData)
   145  	defer closeResponse(resp)
   146  	if err != nil {
   147  		return err
   148  	}
   149  
   150  	if resp.StatusCode != http.StatusNoContent {
   151  		return httpRespToErrorResponse(resp)
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  // RemoveTier removes an empty tier identified by tierName
   158  func (adm *AdminClient) RemoveTier(ctx context.Context, tierName string) error {
   159  	if tierName == "" {
   160  		return ErrTierNameEmpty
   161  	}
   162  	reqData := requestData{
   163  		relPath: path.Join(adminAPIPrefix, tierAPI, tierName),
   164  	}
   165  
   166  	// Execute DELETE on /minio/admin/v3/tier/tierName to remove an empty tier.
   167  	resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData)
   168  	defer closeResponse(resp)
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	if resp.StatusCode != http.StatusNoContent {
   174  		return httpRespToErrorResponse(resp)
   175  	}
   176  
   177  	return nil
   178  }
   179  
   180  // VerifyTier verifies tierName's remote tier config
   181  func (adm *AdminClient) VerifyTier(ctx context.Context, tierName string) error {
   182  	if tierName == "" {
   183  		return ErrTierNameEmpty
   184  	}
   185  	reqData := requestData{
   186  		relPath: path.Join(adminAPIPrefix, tierAPI, tierName),
   187  	}
   188  
   189  	// Execute GET on /minio/admin/v3/tier/tierName to verify tierName's config.
   190  	resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
   191  	defer closeResponse(resp)
   192  	if err != nil {
   193  		return err
   194  	}
   195  
   196  	if resp.StatusCode != http.StatusNoContent {
   197  		return httpRespToErrorResponse(resp)
   198  	}
   199  
   200  	return nil
   201  }
   202  
   203  // TierInfo contains tier name, type and statistics
   204  type TierInfo struct {
   205  	Name       string
   206  	Type       string
   207  	Stats      TierStats
   208  	DailyStats DailyTierStats
   209  }
   210  
   211  type DailyTierStats struct {
   212  	Bins      [24]TierStats
   213  	UpdatedAt time.Time
   214  }
   215  
   216  // TierStats returns per-tier stats of all configured tiers (incl. internal
   217  // hot-tier)
   218  func (adm *AdminClient) TierStats(ctx context.Context) ([]TierInfo, error) {
   219  	reqData := requestData{
   220  		relPath: path.Join(adminAPIPrefix, "tier-stats"),
   221  	}
   222  
   223  	// Execute GET on /minio/admin/v3/tier-stats to list tier-stats.
   224  	resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
   225  	defer closeResponse(resp)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  
   230  	if resp.StatusCode != http.StatusOK {
   231  		return nil, httpRespToErrorResponse(resp)
   232  	}
   233  
   234  	var tierInfos []TierInfo
   235  	b, err := io.ReadAll(resp.Body)
   236  	if err != nil {
   237  		return tierInfos, err
   238  	}
   239  
   240  	err = json.Unmarshal(b, &tierInfos)
   241  	if err != nil {
   242  		return tierInfos, err
   243  	}
   244  
   245  	return tierInfos, nil
   246  }