github.com/minio/madmin-go@v1.7.5/tier.go (about) 1 // 2 // MinIO Object Storage (c) 2021 MinIO, Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 package madmin 18 19 import ( 20 "context" 21 "encoding/json" 22 "io/ioutil" 23 "net/http" 24 "path" 25 "time" 26 ) 27 28 // tierAPI is API path prefix for tier related admin APIs 29 const tierAPI = "tier" 30 31 // AddTier adds a new remote tier. 32 func (adm *AdminClient) AddTier(ctx context.Context, cfg *TierConfig) error { 33 data, err := json.Marshal(cfg) 34 if err != nil { 35 return err 36 } 37 38 encData, err := EncryptData(adm.getSecretKey(), data) 39 if err != nil { 40 return err 41 } 42 43 reqData := requestData{ 44 relPath: path.Join(adminAPIPrefix, tierAPI), 45 content: encData, 46 } 47 48 // Execute PUT on /minio/admin/v3/tier to add a remote tier 49 resp, err := adm.executeMethod(ctx, http.MethodPut, reqData) 50 defer closeResponse(resp) 51 if err != nil { 52 return err 53 } 54 55 if resp.StatusCode != http.StatusNoContent { 56 return httpRespToErrorResponse(resp) 57 } 58 return nil 59 } 60 61 // ListTiers returns a list of remote tiers configured. 62 func (adm *AdminClient) ListTiers(ctx context.Context) ([]*TierConfig, error) { 63 reqData := requestData{ 64 relPath: path.Join(adminAPIPrefix, tierAPI), 65 } 66 67 // Execute GET on /minio/admin/v3/tier to list remote tiers configured. 68 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 69 defer closeResponse(resp) 70 if err != nil { 71 return nil, err 72 } 73 74 if resp.StatusCode != http.StatusOK { 75 return nil, httpRespToErrorResponse(resp) 76 } 77 78 var tiers []*TierConfig 79 b, err := ioutil.ReadAll(resp.Body) 80 if err != nil { 81 return tiers, err 82 } 83 84 err = json.Unmarshal(b, &tiers) 85 if err != nil { 86 return tiers, err 87 } 88 89 return tiers, nil 90 } 91 92 // TierCreds is used to pass remote tier credentials in a tier-edit operation. 93 type TierCreds struct { 94 AccessKey string `json:"access,omitempty"` 95 SecretKey string `json:"secret,omitempty"` 96 CredsJSON []byte `json:"creds,omitempty"` 97 AWSRole bool `json:"awsrole"` 98 } 99 100 // EditTier supports updating credentials for the remote tier identified by tierName. 101 func (adm *AdminClient) EditTier(ctx context.Context, tierName string, creds TierCreds) error { 102 data, err := json.Marshal(creds) 103 if err != nil { 104 return err 105 } 106 107 var encData []byte 108 encData, err = EncryptData(adm.getSecretKey(), data) 109 if err != nil { 110 return err 111 } 112 113 reqData := requestData{ 114 relPath: path.Join(adminAPIPrefix, tierAPI, tierName), 115 content: encData, 116 } 117 118 // Execute POST on /minio/admin/v3/tier/tierName to edit a tier 119 // configured. 120 resp, err := adm.executeMethod(ctx, http.MethodPost, reqData) 121 defer closeResponse(resp) 122 if err != nil { 123 return err 124 } 125 126 if resp.StatusCode != http.StatusNoContent { 127 return httpRespToErrorResponse(resp) 128 } 129 130 return nil 131 } 132 133 // RemoveTier removes an empty tier identified by tierName 134 func (adm *AdminClient) RemoveTier(ctx context.Context, tierName string) error { 135 if tierName == "" { 136 return ErrTierNameEmpty 137 } 138 reqData := requestData{ 139 relPath: path.Join(adminAPIPrefix, tierAPI, tierName), 140 } 141 142 // Execute DELETE on /minio/admin/v3/tier/tierName to remove an empty tier. 143 resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData) 144 defer closeResponse(resp) 145 if err != nil { 146 return err 147 } 148 149 if resp.StatusCode != http.StatusNoContent { 150 return httpRespToErrorResponse(resp) 151 } 152 153 return nil 154 } 155 156 // VerifyTier verifies tierName's remote tier config 157 func (adm *AdminClient) VerifyTier(ctx context.Context, tierName string) error { 158 if tierName == "" { 159 return ErrTierNameEmpty 160 } 161 reqData := requestData{ 162 relPath: path.Join(adminAPIPrefix, tierAPI, tierName), 163 } 164 165 // Execute GET on /minio/admin/v3/tier/tierName to verify tierName's config. 166 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 167 defer closeResponse(resp) 168 if err != nil { 169 return err 170 } 171 172 if resp.StatusCode != http.StatusNoContent { 173 return httpRespToErrorResponse(resp) 174 } 175 176 return nil 177 } 178 179 // TierInfo contains tier name, type and statistics 180 type TierInfo struct { 181 Name string 182 Type string 183 Stats TierStats 184 DailyStats DailyTierStats 185 } 186 187 type DailyTierStats struct { 188 Bins [24]TierStats 189 UpdatedAt time.Time 190 } 191 192 // TierStats returns per-tier stats of all configured tiers (incl. internal 193 // hot-tier) 194 func (adm *AdminClient) TierStats(ctx context.Context) ([]TierInfo, error) { 195 reqData := requestData{ 196 relPath: path.Join(adminAPIPrefix, "tier-stats"), 197 } 198 199 // Execute GET on /minio/admin/v3/tier-stats to list tier-stats. 200 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 201 defer closeResponse(resp) 202 if err != nil { 203 return nil, err 204 } 205 206 if resp.StatusCode != http.StatusOK { 207 return nil, httpRespToErrorResponse(resp) 208 } 209 210 var tierInfos []TierInfo 211 b, err := ioutil.ReadAll(resp.Body) 212 if err != nil { 213 return tierInfos, err 214 } 215 216 err = json.Unmarshal(b, &tierInfos) 217 if err != nil { 218 return tierInfos, err 219 } 220 221 return tierInfos, nil 222 }