github.com/minio/madmin-go@v1.7.5/service-commands.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 "net/http" 23 "net/url" 24 "strconv" 25 "strings" 26 "time" 27 ) 28 29 // ServiceRestart - restarts the MinIO cluster 30 func (adm *AdminClient) ServiceRestart(ctx context.Context) error { 31 return adm.serviceCallAction(ctx, ServiceActionRestart) 32 } 33 34 // ServiceStop - stops the MinIO cluster 35 func (adm *AdminClient) ServiceStop(ctx context.Context) error { 36 return adm.serviceCallAction(ctx, ServiceActionStop) 37 } 38 39 // ServiceFreeze - freezes all incoming S3 API calls on MinIO cluster 40 func (adm *AdminClient) ServiceFreeze(ctx context.Context) error { 41 return adm.serviceCallAction(ctx, ServiceActionFreeze) 42 } 43 44 // ServiceUnfreeze - un-freezes all incoming S3 API calls on MinIO cluster 45 func (adm *AdminClient) ServiceUnfreeze(ctx context.Context) error { 46 return adm.serviceCallAction(ctx, ServiceActionUnfreeze) 47 } 48 49 // ServiceAction - type to restrict service-action values 50 type ServiceAction string 51 52 const ( 53 // ServiceActionRestart represents restart action 54 ServiceActionRestart ServiceAction = "restart" 55 // ServiceActionStop represents stop action 56 ServiceActionStop = "stop" 57 // ServiceActionFreeze represents freeze action 58 ServiceActionFreeze = "freeze" 59 // ServiceActionUnfreeze represents unfreeze a previous freeze action 60 ServiceActionUnfreeze = "unfreeze" 61 ) 62 63 // serviceCallAction - call service restart/update/stop API. 64 func (adm *AdminClient) serviceCallAction(ctx context.Context, action ServiceAction) error { 65 queryValues := url.Values{} 66 queryValues.Set("action", string(action)) 67 68 // Request API to Restart server 69 resp, err := adm.executeMethod(ctx, 70 http.MethodPost, requestData{ 71 relPath: adminAPIPrefix + "/service", 72 queryValues: queryValues, 73 }, 74 ) 75 defer closeResponse(resp) 76 if err != nil { 77 return err 78 } 79 80 if resp.StatusCode != http.StatusOK { 81 return httpRespToErrorResponse(resp) 82 } 83 84 return nil 85 } 86 87 // ServiceTraceInfo holds http trace 88 type ServiceTraceInfo struct { 89 Trace TraceInfo 90 Err error `json:"-"` 91 } 92 93 // ServiceTraceOpts holds tracing options 94 type ServiceTraceOpts struct { 95 // Trace types: 96 S3 bool 97 Internal bool 98 Storage bool 99 OS bool 100 Scanner bool 101 Decommission bool 102 Healing bool 103 BatchReplication bool 104 Rebalance bool 105 ReplicationResync bool 106 OnlyErrors bool 107 Threshold time.Duration 108 } 109 110 // TraceTypes returns the enabled traces as a bitfield value. 111 func (t ServiceTraceOpts) TraceTypes() TraceType { 112 var tt TraceType 113 tt.SetIf(t.S3, TraceS3) 114 tt.SetIf(t.Internal, TraceInternal) 115 tt.SetIf(t.Storage, TraceStorage) 116 tt.SetIf(t.OS, TraceOS) 117 tt.SetIf(t.Scanner, TraceScanner) 118 tt.SetIf(t.Decommission, TraceDecommission) 119 tt.SetIf(t.Healing, TraceHealing) 120 tt.SetIf(t.BatchReplication, TraceBatchReplication) 121 tt.SetIf(t.Rebalance, TraceRebalance) 122 tt.SetIf(t.ReplicationResync, TraceReplicationResync) 123 124 return tt 125 } 126 127 // AddParams will add parameter to url values. 128 func (t ServiceTraceOpts) AddParams(u url.Values) { 129 u.Set("err", strconv.FormatBool(t.OnlyErrors)) 130 u.Set("threshold", t.Threshold.String()) 131 132 u.Set("s3", strconv.FormatBool(t.S3)) 133 u.Set("internal", strconv.FormatBool(t.Internal)) 134 u.Set("storage", strconv.FormatBool(t.Storage)) 135 u.Set("os", strconv.FormatBool(t.OS)) 136 u.Set("scanner", strconv.FormatBool(t.Scanner)) 137 u.Set("decommission", strconv.FormatBool(t.Decommission)) 138 u.Set("healing", strconv.FormatBool(t.Healing)) 139 u.Set("batch-replication", strconv.FormatBool(t.BatchReplication)) 140 u.Set("rebalance", strconv.FormatBool(t.Rebalance)) 141 u.Set("replication-resync", strconv.FormatBool(t.ReplicationResync)) 142 } 143 144 // ParseParams will parse parameters and set them to t. 145 func (t *ServiceTraceOpts) ParseParams(r *http.Request) (err error) { 146 t.S3 = r.Form.Get("s3") == "true" 147 t.OS = r.Form.Get("os") == "true" 148 t.Scanner = r.Form.Get("scanner") == "true" 149 t.Decommission = r.Form.Get("decommission") == "true" 150 t.Healing = r.Form.Get("healing") == "true" 151 t.BatchReplication = r.Form.Get("batch-replication") == "true" 152 t.Rebalance = r.Form.Get("rebalance") == "true" 153 t.Storage = r.Form.Get("storage") == "true" 154 t.Internal = r.Form.Get("internal") == "true" 155 t.OnlyErrors = r.Form.Get("err") == "true" 156 t.ReplicationResync = r.Form.Get("replication-resync") == "true" 157 158 if th := r.Form.Get("threshold"); th != "" { 159 d, err := time.ParseDuration(th) 160 if err != nil { 161 return err 162 } 163 t.Threshold = d 164 } 165 return nil 166 } 167 168 // ServiceTrace - listen on http trace notifications. 169 func (adm AdminClient) ServiceTrace(ctx context.Context, opts ServiceTraceOpts) <-chan ServiceTraceInfo { 170 traceInfoCh := make(chan ServiceTraceInfo) 171 // Only success, start a routine to start reading line by line. 172 go func(traceInfoCh chan<- ServiceTraceInfo) { 173 defer close(traceInfoCh) 174 for { 175 urlValues := make(url.Values) 176 opts.AddParams(urlValues) 177 178 reqData := requestData{ 179 relPath: adminAPIPrefix + "/trace", 180 queryValues: urlValues, 181 } 182 // Execute GET to call trace handler 183 resp, err := adm.executeMethod(ctx, http.MethodGet, reqData) 184 if err != nil { 185 traceInfoCh <- ServiceTraceInfo{Err: err} 186 return 187 } 188 189 if resp.StatusCode != http.StatusOK { 190 closeResponse(resp) 191 traceInfoCh <- ServiceTraceInfo{Err: httpRespToErrorResponse(resp)} 192 return 193 } 194 195 dec := json.NewDecoder(resp.Body) 196 for { 197 var info traceInfoLegacy 198 if err = dec.Decode(&info); err != nil { 199 closeResponse(resp) 200 traceInfoCh <- ServiceTraceInfo{Err: err} 201 break 202 } 203 // Convert if legacy... 204 if info.TraceType == TraceType(0) { 205 if strings.HasPrefix(info.FuncName, "s3.") { 206 info.TraceType = TraceS3 207 } else { 208 info.TraceType = TraceInternal 209 } 210 info.HTTP = &TraceHTTPStats{} 211 if info.ReqInfo != nil { 212 info.Path = info.ReqInfo.Path 213 info.HTTP.ReqInfo = *info.ReqInfo 214 } 215 if info.RespInfo != nil { 216 info.HTTP.RespInfo = *info.RespInfo 217 } 218 if info.CallStats != nil { 219 info.Duration = info.CallStats.Latency 220 info.HTTP.CallStats = *info.CallStats 221 } 222 } 223 if info.TraceType == TraceOS && info.OSStats != nil { 224 info.Path = info.OSStats.Path 225 info.Duration = info.OSStats.Duration 226 } 227 if info.TraceType == TraceStorage && info.StorageStats != nil { 228 info.Path = info.StorageStats.Path 229 info.Duration = info.StorageStats.Duration 230 } 231 select { 232 case <-ctx.Done(): 233 closeResponse(resp) 234 return 235 case traceInfoCh <- ServiceTraceInfo{Trace: info.TraceInfo}: 236 } 237 } 238 } 239 }(traceInfoCh) 240 241 // Returns the trace info channel, for caller to start reading from. 242 return traceInfoCh 243 }