diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go
index 19780fede..51bd4e431 100644
--- a/cmd/admin-handlers.go
+++ b/cmd/admin-handlers.go
@@ -35,10 +35,12 @@ import (
"github.com/gorilla/mux"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth"
+ "github.com/minio/minio/pkg/cpu"
"github.com/minio/minio/pkg/disk"
"github.com/minio/minio/pkg/handlers"
"github.com/minio/minio/pkg/iam/policy"
"github.com/minio/minio/pkg/madmin"
+ "github.com/minio/minio/pkg/mem"
"github.com/minio/minio/pkg/quick"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
@@ -294,6 +296,24 @@ type ServerDrivesPerfInfo struct {
Perf []disk.Performance `json:"perf"`
}
+// ServerCPULoadInfo holds informantion about cpu utilization
+// of one minio node. It also reports any errors if encountered
+// while trying to reach this server.
+type ServerCPULoadInfo struct {
+ Addr string `json:"addr"`
+ Error string `json:"error,omitempty"`
+ Load []cpu.Load `json:"load"`
+}
+
+// ServerMemUsageInfo holds informantion about memory utilization
+// of one minio node. It also reports any errors if encountered
+// while trying to reach this server.
+type ServerMemUsageInfo struct {
+ Addr string `json:"addr"`
+ Error string `json:"error,omitempty"`
+ Usage []mem.Usage `json:"usage"`
+}
+
// PerfInfoHandler - GET /minio/admin/v1/performance?perfType={perfType}
// ----------
// Get all performance information based on input type
@@ -301,6 +321,13 @@ type ServerDrivesPerfInfo struct {
func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "PerfInfo")
+ // Get object layer instance.
+ objLayer := newObjectLayerFn()
+ if objLayer == nil {
+ writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL)
+ return
+ }
+
// Authenticate request
// Setting the region as empty so as the mc server info command is irrespective to the region.
adminAPIErr := checkAdminRequestAuthType(ctx, r, "")
@@ -313,8 +340,14 @@ func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request
perfType := vars["perfType"]
if perfType == "drive" {
+ info := objLayer.StorageInfo(ctx)
+ if !(info.Backend.Type == BackendFS || info.Backend.Type == BackendErasure) {
+
+ writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL)
+ return
+ }
// Get drive performance details from local server's drive(s)
- dp := localEndpointsPerf(globalEndpoints)
+ dp := localEndpointsDrivePerf(globalEndpoints)
// Notify all other Minio peers to report drive performance numbers
dps := globalNotificationSys.DrivePerfInfo()
@@ -330,8 +363,42 @@ func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request
// Reply with performance information (across nodes in a
// distributed setup) as json.
writeSuccessResponseJSON(w, jsonBytes)
+ } else if perfType == "cpu" {
+ // Get CPU load details from local server's cpu(s)
+ cpu := localEndpointsCPULoad(globalEndpoints)
+ // Notify all other Minio peers to report cpu load numbers
+ cpus := globalNotificationSys.CPULoadInfo()
+ cpus = append(cpus, cpu)
+
+ // Marshal API response
+ jsonBytes, err := json.Marshal(cpus)
+ if err != nil {
+ writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL)
+ return
+ }
+
+ // Reply with cpu load information (across nodes in a
+ // distributed setup) as json.
+ writeSuccessResponseJSON(w, jsonBytes)
+ } else if perfType == "mem" {
+ // Get mem usage details from local server(s)
+ m := localEndpointsMemUsage(globalEndpoints)
+ // Notify all other Minio peers to report mem usage numbers
+ mems := globalNotificationSys.MemUsageInfo()
+ mems = append(mems, m)
+
+ // Marshal API response
+ jsonBytes, err := json.Marshal(mems)
+ if err != nil {
+ writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL)
+ return
+ }
+
+ // Reply with mem usage information (across nodes in a
+ // distributed setup) as json.
+ writeSuccessResponseJSON(w, jsonBytes)
} else {
- writeErrorResponseJSON(w, ErrNotImplemented, r.URL)
+ writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL)
}
return
}
diff --git a/cmd/admin-router.go b/cmd/admin-router.go
index 068630073..175b77f13 100644
--- a/cmd/admin-router.go
+++ b/cmd/admin-router.go
@@ -63,9 +63,9 @@ func registerAdminRouter(router *mux.Router, enableIAM bool) {
/// Health operations
- // Performance command - return performance details based on input type
- adminV1Router.Methods(http.MethodGet).Path("/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}")
}
+ // Performance command - return performance details based on input type
+ adminV1Router.Methods(http.MethodGet).Path("/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}")
// Profiling operations
adminV1Router.Methods(http.MethodPost).Path("/profiling/start").HandlerFunc(httpTraceAll(adminAPI.StartProfilingHandler)).
diff --git a/cmd/endpoint.go b/cmd/endpoint.go
index 7bfaa6615..ab17edc99 100644
--- a/cmd/endpoint.go
+++ b/cmd/endpoint.go
@@ -29,7 +29,9 @@ import (
"github.com/minio/minio-go/pkg/set"
"github.com/minio/minio/cmd/logger"
+ "github.com/minio/minio/pkg/cpu"
"github.com/minio/minio/pkg/disk"
+ "github.com/minio/minio/pkg/mem"
"github.com/minio/minio/pkg/mountinfo"
)
@@ -198,9 +200,57 @@ func (endpoints EndpointList) GetString(i int) string {
return endpoints[i].String()
}
-// localEndpointsPerf - returns ServerDrivesPerfInfo for only the
+// localEndpointsMemUsage - returns ServerMemUsageInfo for only the
// local endpoints from given list of endpoints
-func localEndpointsPerf(endpoints EndpointList) ServerDrivesPerfInfo {
+func localEndpointsMemUsage(endpoints EndpointList) ServerMemUsageInfo {
+ var memUsages []mem.Usage
+ var addr string
+ scratchSpace := map[string]bool{}
+ for _, endpoint := range endpoints {
+ // Only proceed for local endpoints
+ if endpoint.IsLocal {
+ if _, ok := scratchSpace[endpoint.Host]; ok {
+ continue
+ }
+ addr = GetLocalPeer(endpoints)
+ memUsage := mem.GetUsage()
+ memUsages = append(memUsages, memUsage)
+ scratchSpace[endpoint.Host] = true
+ }
+ }
+ return ServerMemUsageInfo{
+ Addr: addr,
+ Usage: memUsages,
+ }
+}
+
+// localEndpointsCPULoad - returns ServerCPULoadInfo for only the
+// local endpoints from given list of endpoints
+func localEndpointsCPULoad(endpoints EndpointList) ServerCPULoadInfo {
+ var cpuLoads []cpu.Load
+ var addr string
+ scratchSpace := map[string]bool{}
+ for _, endpoint := range endpoints {
+ // Only proceed for local endpoints
+ if endpoint.IsLocal {
+ if _, ok := scratchSpace[endpoint.Host]; ok {
+ continue
+ }
+ addr = GetLocalPeer(endpoints)
+ cpuLoad := cpu.GetLoad()
+ cpuLoads = append(cpuLoads, cpuLoad)
+ scratchSpace[endpoint.Host] = true
+ }
+ }
+ return ServerCPULoadInfo{
+ Addr: addr,
+ Load: cpuLoads,
+ }
+}
+
+// localEndpointsDrivePerf - returns ServerDrivesPerfInfo for only the
+// local endpoints from given list of endpoints
+func localEndpointsDrivePerf(endpoints EndpointList) ServerDrivesPerfInfo {
var dps []disk.Performance
var addr string
for _, endpoint := range endpoints {
diff --git a/cmd/notification.go b/cmd/notification.go
index 24938a329..8ad2e2eea 100644
--- a/cmd/notification.go
+++ b/cmd/notification.go
@@ -537,6 +537,56 @@ func (sys *NotificationSys) DrivePerfInfo() []ServerDrivesPerfInfo {
return reply
}
+// MemUsageInfo - Mem utilization information
+func (sys *NotificationSys) MemUsageInfo() []ServerMemUsageInfo {
+ reply := make([]ServerMemUsageInfo, len(sys.peerRPCClientMap))
+ var wg sync.WaitGroup
+ var i int
+ for addr, client := range sys.peerRPCClientMap {
+ wg.Add(1)
+ go func(addr xnet.Host, client *PeerRPCClient, idx int) {
+ defer wg.Done()
+ memi, err := client.MemUsageInfo()
+ if err != nil {
+ reqInfo := (&logger.ReqInfo{}).AppendTags("remotePeer", addr.String())
+ ctx := logger.SetReqInfo(context.Background(), reqInfo)
+ logger.LogIf(ctx, err)
+ memi.Addr = addr.String()
+ memi.Error = err.Error()
+ }
+ reply[idx] = memi
+ }(addr, client, i)
+ i++
+ }
+ wg.Wait()
+ return reply
+}
+
+// CPULoadInfo - CPU utilization information
+func (sys *NotificationSys) CPULoadInfo() []ServerCPULoadInfo {
+ reply := make([]ServerCPULoadInfo, len(sys.peerRPCClientMap))
+ var wg sync.WaitGroup
+ var i int
+ for addr, client := range sys.peerRPCClientMap {
+ wg.Add(1)
+ go func(addr xnet.Host, client *PeerRPCClient, idx int) {
+ defer wg.Done()
+ cpui, err := client.CPULoadInfo()
+ if err != nil {
+ reqInfo := (&logger.ReqInfo{}).AppendTags("remotePeer", addr.String())
+ ctx := logger.SetReqInfo(context.Background(), reqInfo)
+ logger.LogIf(ctx, err)
+ cpui.Addr = addr.String()
+ cpui.Error = err.Error()
+ }
+ reply[idx] = cpui
+ }(addr, client, i)
+ i++
+ }
+ wg.Wait()
+ return reply
+}
+
// NewNotificationSys - creates new notification system object.
func NewNotificationSys(config *serverConfig, endpoints EndpointList) *NotificationSys {
targetList := getNotificationTargets(config)
diff --git a/cmd/peer-rpc-client.go b/cmd/peer-rpc-client.go
index ea8d2909c..4b71473c7 100644
--- a/cmd/peer-rpc-client.go
+++ b/cmd/peer-rpc-client.go
@@ -150,6 +150,24 @@ func (rpcClient *PeerRPCClient) DrivePerfInfo() (ServerDrivesPerfInfo, error) {
return reply, err
}
+// MemUsageInfo - returns mem utilization info for remote server
+func (rpcClient *PeerRPCClient) MemUsageInfo() (ServerMemUsageInfo, error) {
+ args := AuthArgs{}
+ var reply ServerMemUsageInfo
+
+ err := rpcClient.Call(peerServiceName+".MemUsageInfo", &args, &reply)
+ return reply, err
+}
+
+// CPULoadInfo - returns cpu performance info for remote server
+func (rpcClient *PeerRPCClient) CPULoadInfo() (ServerCPULoadInfo, error) {
+ args := AuthArgs{}
+ var reply ServerCPULoadInfo
+
+ err := rpcClient.Call(peerServiceName+".CPULoadInfo", &args, &reply)
+ return reply, err
+}
+
// NewPeerRPCClient - returns new peer RPC client.
func NewPeerRPCClient(host *xnet.Host) (*PeerRPCClient, error) {
scheme := "http"
diff --git a/cmd/peer-rpc-server.go b/cmd/peer-rpc-server.go
index e0b40af9f..b267cf13e 100644
--- a/cmd/peer-rpc-server.go
+++ b/cmd/peer-rpc-server.go
@@ -245,7 +245,27 @@ func (receiver *peerRPCReceiver) DrivePerfInfo(args *AuthArgs, reply *ServerDriv
return errServerNotInitialized
}
- *reply = localEndpointsPerf(globalEndpoints)
+ *reply = localEndpointsDrivePerf(globalEndpoints)
+ return nil
+}
+
+// CPULoadInfo - handles cpu performance RPC call
+func (receiver *peerRPCReceiver) CPULoadInfo(args *AuthArgs, reply *ServerCPULoadInfo) error {
+ objAPI := newObjectLayerFn()
+ if objAPI == nil {
+ return errServerNotInitialized
+ }
+ *reply = localEndpointsCPULoad(globalEndpoints)
+ return nil
+}
+
+// MemUsageInfo - handles mem utilization RPC call
+func (receiver *peerRPCReceiver) MemUsageInfo(args *AuthArgs, reply *ServerMemUsageInfo) error {
+ objAPI := newObjectLayerFn()
+ if objAPI == nil {
+ return errServerNotInitialized
+ }
+ *reply = localEndpointsMemUsage(globalEndpoints)
return nil
}
diff --git a/pkg/cpu/counter_darwin.go b/pkg/cpu/counter_darwin.go
new file mode 100644
index 000000000..2968c8cd3
--- /dev/null
+++ b/pkg/cpu/counter_darwin.go
@@ -0,0 +1,29 @@
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cpu
+
+import (
+ "errors"
+)
+
+func newCounter() (counter, error) {
+ return counter{}, errors.New("cpu metrics not implemented for darwin platform")
+}
+
+func (c counter) now() time.Time {
+ return time.Time{}
+}
diff --git a/pkg/cpu/counter_linux.go b/pkg/cpu/counter_linux.go
new file mode 100644
index 000000000..2a9f97d72
--- /dev/null
+++ b/pkg/cpu/counter_linux.go
@@ -0,0 +1,40 @@
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cpu
+
+import (
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+const (
+ // ProcessClock corresponds to the High-resolution per-process
+ // timer from the CPU represented in stdlib as CLOCK_PROCESS_CPUTIME_ID
+ processClock = 2
+)
+
+func newCounter() (counter, error) {
+ return counter{}, nil
+}
+
+func (c counter) now() time.Time {
+ var ts syscall.Timespec
+ syscall.Syscall(syscall.SYS_CLOCK_GETTIME, processClock, uintptr(unsafe.Pointer(&ts)), 0)
+ sec, nsec := ts.Unix()
+ return time.Unix(sec, nsec)
+}
diff --git a/pkg/cpu/counter_windows.go b/pkg/cpu/counter_windows.go
new file mode 100644
index 000000000..0ee5cbc68
--- /dev/null
+++ b/pkg/cpu/counter_windows.go
@@ -0,0 +1,30 @@
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cpu
+
+import (
+ "errors"
+ "time"
+)
+
+func newCounter() (counter, error) {
+ return counter{}, errors.New("cpu metrics not implemented for windows platform")
+}
+
+func (c counter) now() time.Time {
+ return time.Time{}
+}
diff --git a/pkg/cpu/cpu.go b/pkg/cpu/cpu.go
new file mode 100644
index 000000000..147aab3df
--- /dev/null
+++ b/pkg/cpu/cpu.go
@@ -0,0 +1,91 @@
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cpu
+
+import (
+ "fmt"
+ "sync"
+ "time"
+)
+
+const (
+ // cpuLoadWindow is the interval of time for which the
+ // cpu utilization is measured
+ cpuLoadWindow = 200 * time.Millisecond
+
+ // cpuLoadSampleSize is the number of samples measured
+ // for calculating cpu utilization
+ cpuLoadSampleSize = 3
+
+ // endOfTime represents the end of time
+ endOfTime = time.Duration(1<<63 - 1)
+)
+
+// Load holds CPU utilization % measured in three intervals of 200ms each
+type Load struct {
+ Avg string `json:"avg"`
+ Max string `json:"max"`
+ Min string `json:"min"`
+ Error string `json:"error,omitempty"`
+}
+
+type counter struct{}
+
+// GetLoad returns the CPU utilization % of the current process
+func GetLoad() Load {
+ vals := make(chan time.Duration, 3)
+ wg := sync.WaitGroup{}
+ for i := 0; i < cpuLoadSampleSize; i++ {
+ cpuCounter, err := newCounter()
+ if err != nil {
+ return Load{
+ Error: err.Error(),
+ }
+ }
+ wg.Add(1)
+ go func() {
+ start := cpuCounter.now()
+ time.Sleep(cpuLoadWindow)
+ end := cpuCounter.now()
+ vals <- end.Sub(start)
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+
+ sum := time.Duration(0)
+ max := time.Duration(0)
+ min := (endOfTime)
+ for i := 0; i < cpuLoadSampleSize; i++ {
+ val := <-vals
+ sum = sum + val
+ if val > max {
+ max = val
+ }
+ if val < min {
+ min = val
+ }
+ }
+ close(vals)
+ avg := sum / 3
+ return Load{
+ Avg: fmt.Sprintf("%.2f%%", toFixed4(float64(avg)/float64(200*time.Millisecond))*100),
+ Max: fmt.Sprintf("%.2f%%", toFixed4(float64(max)/float64(200*time.Millisecond))*100),
+ Min: fmt.Sprintf("%.2f%%", toFixed4(float64(min)/float64(200*time.Millisecond))*100),
+ Error: "",
+ }
+}
diff --git a/pkg/cpu/helpers.go b/pkg/cpu/helpers.go
new file mode 100644
index 000000000..96eb2466b
--- /dev/null
+++ b/pkg/cpu/helpers.go
@@ -0,0 +1,30 @@
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cpu
+
+import (
+ "math"
+)
+
+func round(num float64) int {
+ return int(num + math.Copysign(0.5, num))
+}
+
+func toFixed4(num float64) float64 {
+ output := math.Pow(10, float64(4))
+ return float64(round(num*output)) / output
+}
diff --git a/pkg/madmin/API.md b/pkg/madmin/API.md
index 0f8b1ecb5..c8c239931 100644
--- a/pkg/madmin/API.md
+++ b/pkg/madmin/API.md
@@ -39,7 +39,7 @@ func main() {
| Service operations | Info operations | Healing operations | Config operations | IAM operations | Misc |
|:----------------------------|:----------------------------|:--------------------------------------|:--------------------------|:------------------------------------|:------------------------------------|
| [`ServiceStatus`](#ServiceStatus) | [`ServerInfo`](#ServerInfo) | [`Heal`](#Heal) | [`GetConfig`](#GetConfig) | [`AddUser`](#AddUser) | [`SetAdminCredentials`](#SetAdminCredentials) |
-| [`ServiceSendAction`](#ServiceSendAction) | [`ServerDrivesPerfInfo`](#ServerDrivesPerfInfo) | [`SetConfig`](#SetConfig) | [`SetUserPolicy`](#SetUserPolicy) | [`StartProfiling`](#StartProfiling) |
+| [`ServiceSendAction`](#ServiceSendAction) | [`ServerDrivesPerfInfo`](#ServerDrivesPerfInfo) | [`ServerCPULoadInfo`](#ServerCPULoadInfo) | [`ServerMemUsageInfo`](#ServerMemUsageInfo) | [`SetConfig`](#SetConfig) | [`SetUserPolicy`](#SetUserPolicy) | [`StartProfiling`](#StartProfiling) |
| | | | [`GetConfigKeys`](#GetConfigKeys) | [`ListUsers`](#ListUsers) | [`DownloadProfilingData`](#DownloadProfilingData) |
| | | | [`SetConfigKeys`](#SetConfigKeys) | [`AddCannedPolicy`](#AddCannedPolicy) | |
@@ -222,6 +222,40 @@ Fetches drive performance information for all cluster nodes. Returned value is i
|`disk.Performance.WriteSpeed` | _float64_ | Write speed on above path in Bytes/s. |
|`disk.Performance.ReadSpeed` | _float64_ | Read speed on above path in Bytes/s. |
+
+### ServerCPULoadInfo() ([]ServerCPULoadInfo, error)
+
+Fetches CPU utilization for all cluster nodes. Returned value is in Bytes.
+
+| Param | Type | Description |
+|-------|------|-------------|
+|`cpui.Addr` | _string_ | Address of the server the following information is retrieved from. |
+|`cpui.Error` | _string_ | Errors (if any) encountered while reaching this node |
+|`cpui.CPULoad` | _cpu.Load_ | The load on the CPU. |
+
+| Param | Type | Description |
+|-------|------|-------------|
+|`cpu.Load.Avg` | _string_ | The average utilization % of the CPU measured in a 200ms interval |
+|`cpu.Load.Min` | _string_ | The minimum utilization % of the CPU measured in a 200ms interval |
+|`cpu.Load.Max` | _string_ | The maximum utilization % of the CPU measured in a 200ms interval |
+|`cpu.Load.Error` | _string_ | Error (if any) encountered while accesing the CPU info |
+
+
+### ServerMemUsageInfo() ([]ServerMemUsageInfo, error)
+
+Fetches Mem utilization for all cluster nodes. Returned value is in Bytes.
+
+| Param | Type | Description |
+|-------|------|-------------|
+|`memi.Addr` | _string_ | Address of the server the following information is retrieved from. |
+|`memi.Error` | _string_ | Errors (if any) encountered while reaching this node |
+|`memi.MemUsage` | _mem.Usage_ | The utilitzation of Memory |
+
+| Param | Type | Description |
+|-------|------|-------------|
+|`mem.Usage.Mem` | _string_ | The total number of bytes obtained from the OS |
+|`mem.Usage.Error` | _string_ | Error (if any) encountered while accesing the CPU info |
+
## 6. Heal operations
diff --git a/pkg/madmin/examples/cpu-load-info.go b/pkg/madmin/examples/cpu-load-info.go
new file mode 100644
index 000000000..d59287540
--- /dev/null
+++ b/pkg/madmin/examples/cpu-load-info.go
@@ -0,0 +1,44 @@
+// +build ignore
+
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package main
+
+import (
+ "log"
+
+ "github.com/minio/minio/pkg/madmin"
+)
+
+func main() {
+ // Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY and my-bucketname are
+ // dummy values, please replace them with original values.
+
+ // API requests are secure (HTTPS) if secure=true and insecure (HTTPS) otherwise.
+ // New returns an Minio Admin client object.
+ madmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true)
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ st, err := madmClnt.ServerCPULoadInfo()
+ if err != nil {
+ log.Fatalln(err)
+ }
+ log.Println(st)
+}
diff --git a/pkg/madmin/examples/mem-usage-info.go b/pkg/madmin/examples/mem-usage-info.go
new file mode 100644
index 000000000..9e6f9bc59
--- /dev/null
+++ b/pkg/madmin/examples/mem-usage-info.go
@@ -0,0 +1,44 @@
+// +build ignore
+
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package main
+
+import (
+ "log"
+
+ "github.com/minio/minio/pkg/madmin"
+)
+
+func main() {
+ // Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY and my-bucketname are
+ // dummy values, please replace them with original values.
+
+ // API requests are secure (HTTPS) if secure=true and insecure (HTTPS) otherwise.
+ // New returns an Minio Admin client object.
+ madmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true)
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ st, err := madmClnt.ServerMemUsageInfo()
+ if err != nil {
+ log.Fatalln(err)
+ }
+ log.Println(st)
+}
diff --git a/pkg/madmin/info-commands.go b/pkg/madmin/info-commands.go
index e2920341c..b3968117f 100644
--- a/pkg/madmin/info-commands.go
+++ b/pkg/madmin/info-commands.go
@@ -24,7 +24,9 @@ import (
"net/url"
"time"
+ "github.com/minio/minio/pkg/cpu"
"github.com/minio/minio/pkg/disk"
+ "github.com/minio/minio/pkg/mem"
)
// BackendType - represents different backend types.
@@ -193,3 +195,89 @@ func (adm *AdminClient) ServerDrivesPerfInfo() ([]ServerDrivesPerfInfo, error) {
return info, nil
}
+
+// ServerCPULoadInfo holds information about address and cpu load of
+// a single server node
+type ServerCPULoadInfo struct {
+ Addr string `json:"addr"`
+ Error string `json:"error,omitempty"`
+ Load []cpu.Load `json:"load"`
+}
+
+// ServerCPULoadInfo - Returns cpu utilization information
+func (adm *AdminClient) ServerCPULoadInfo() ([]ServerCPULoadInfo, error) {
+ v := url.Values{}
+ v.Set("perfType", string("cpu"))
+ resp, err := adm.executeMethod("GET", requestData{
+ relPath: "/v1/performance",
+ queryValues: v,
+ })
+
+ defer closeResponse(resp)
+ if err != nil {
+ return nil, err
+ }
+
+ // Check response http status code
+ if resp.StatusCode != http.StatusOK {
+ return nil, httpRespToErrorResponse(resp)
+ }
+
+ // Unmarshal the server's json response
+ var info []ServerCPULoadInfo
+
+ respBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ err = json.Unmarshal(respBytes, &info)
+ if err != nil {
+ return nil, err
+ }
+
+ return info, nil
+}
+
+// ServerMemUsageInfo holds information about address and memory utilization of
+// a single server node
+type ServerMemUsageInfo struct {
+ Addr string `json:"addr"`
+ Error string `json:"error,omitempty"`
+ Usage []mem.Usage `json:"usage"`
+}
+
+// ServerMemUsageInfo - Returns mem utilization information
+func (adm *AdminClient) ServerMemUsageInfo() ([]ServerMemUsageInfo, error) {
+ v := url.Values{}
+ v.Set("perfType", string("mem"))
+ resp, err := adm.executeMethod("GET", requestData{
+ relPath: "/v1/performance",
+ queryValues: v,
+ })
+
+ defer closeResponse(resp)
+ if err != nil {
+ return nil, err
+ }
+
+ // Check response http status code
+ if resp.StatusCode != http.StatusOK {
+ return nil, httpRespToErrorResponse(resp)
+ }
+
+ // Unmarshal the server's json response
+ var info []ServerMemUsageInfo
+
+ respBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ err = json.Unmarshal(respBytes, &info)
+ if err != nil {
+ return nil, err
+ }
+
+ return info, nil
+}
diff --git a/pkg/mem/mem.go b/pkg/mem/mem.go
new file mode 100644
index 000000000..95357d626
--- /dev/null
+++ b/pkg/mem/mem.go
@@ -0,0 +1,39 @@
+/*
+ * Minio Cloud Storage, (C) 2019 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package mem
+
+import (
+ "runtime"
+
+ humanize "github.com/dustin/go-humanize"
+)
+
+// Usage holds memory utilization information in human readable format
+type Usage struct {
+ Mem string `json:"mem"`
+ Error string `json:"error,omitempty"`
+}
+
+// GetUsage measures the total memory provisioned for the current process
+// from the OS
+func GetUsage() Usage {
+ memStats := new(runtime.MemStats)
+ runtime.ReadMemStats(memStats)
+ return Usage{
+ Mem: humanize.IBytes(memStats.Sys),
+ }
+}