From 85e15b9c6c9854abe4c09c79943c0bea93989162 Mon Sep 17 00:00:00 2001 From: Alex Aizman Date: Sun, 24 Mar 2024 13:33:27 -0400 Subject: [PATCH] [backward compatibility] v3.22 and prior; bump CLI version * keep v3.22 control structures - denote all of them - attach "v322" or "V322" suffix * REST APIs: node and cluster stats; node and cluster status * refactor `api` pkg - extract stats.go * remove redundant code; simplify Signed-off-by: Alex Aizman --- ais/htrun.go | 50 ++++++++++++++++++ ais/proxy.go | 22 +------- ais/prxclu.go | 2 +- ais/tgtcp.go | 62 ++++++++++++----------- api/apc/query.go | 14 ++++-- api/blob.go | 2 +- api/bsumm.go | 4 +- api/bucket.go | 4 +- api/client.go | 4 +- api/cluster.go | 51 +------------------ api/daemon.go | 68 +------------------------ api/download.go | 4 +- api/dsort.go | 4 +- api/etl.go | 4 +- api/ls.go | 2 +- api/multiobj.go | 2 +- api/object.go | 2 +- api/s3.go | 4 +- api/stats.go | 109 ++++++++++++++++++++++++++++++++++++++++ api/xaction.go | 2 +- cmd/cli/go.mod | 2 +- cmd/cli/go.sum | 4 +- cmn/config.go | 16 +++--- cmn/ver_const.go | 2 +- core/mock/stats_mock.go | 23 +++++---- fs/api.go | 16 ++++++ stats/api.go | 23 +++++++++ stats/common_stats.go | 9 ++++ stats/target_stats.go | 25 ++++++++- 29 files changed, 324 insertions(+), 212 deletions(-) create mode 100644 api/stats.go diff --git a/ais/htrun.go b/ais/htrun.go index 11a072801a..5d10d7c1f5 100644 --- a/ais/htrun.go +++ b/ais/htrun.go @@ -23,6 +23,7 @@ import ( "time" "github.com/NVIDIA/aistore/api/apc" + "github.com/NVIDIA/aistore/api/env" "github.com/NVIDIA/aistore/cmn" "github.com/NVIDIA/aistore/cmn/archive" "github.com/NVIDIA/aistore/cmn/atomic" @@ -1045,8 +1046,22 @@ func (h *htrun) httpdaeget(w http.ResponseWriter, r *http.Request, query url.Val statsNode := h.statsT.GetStats() statsNode.Snode = h.si body = statsNode + case apc.WhatNodeStatsV322: + statsNode := h.statsT.GetStatsV322() + statsNode.Snode = h.si + body = statsNode case apc.WhatMetricNames: body = h.statsT.GetMetricNames() + case apc.WhatNodeStatsAndStatus: + ds := h.statsAndStatus() + daeStats := h.statsT.GetStats() + ds.Tracker = daeStats.Tracker + body = ds + case apc.WhatNodeStatsAndStatusV322: + ds := h.statsAndStatusV322() + daeStats := h.statsT.GetStatsV322() + ds.Tracker = daeStats.Tracker + body = ds default: h.writeErrf(w, r, "invalid GET /daemon request: unrecognized what=%s", what) return @@ -1054,6 +1069,41 @@ func (h *htrun) httpdaeget(w http.ResponseWriter, r *http.Request, query url.Val h.writeJSON(w, r, body, "httpdaeget-"+what) } +func (h *htrun) statsAndStatus() (ds *stats.NodeStatus) { + smap := h.owner.smap.get() + ds = &stats.NodeStatus{ + Node: stats.Node{ + Snode: h.si, + }, + SmapVersion: smap.Version, + MemCPUInfo: apc.GetMemCPU(), + DeploymentType: deploymentType(), + Version: daemon.version, + BuildTime: daemon.buildTime, + K8sPodName: os.Getenv(env.AIS.K8sPod), + Status: h._status(smap), + } + return ds +} + +// [backward compatibility] v3.22 and prior +func (h *htrun) statsAndStatusV322() (ds *stats.NodeStatusV322) { + smap := h.owner.smap.get() + ds = &stats.NodeStatusV322{ + NodeV322: stats.NodeV322{ + Snode: h.si, + }, + SmapVersion: smap.Version, + MemCPUInfo: apc.GetMemCPU(), + DeploymentType: deploymentType(), + Version: daemon.version, + BuildTime: daemon.buildTime, + K8sPodName: os.Getenv(env.AIS.K8sPod), + Status: h._status(smap), + } + return ds +} + func (h *htrun) sendAllLogs(w http.ResponseWriter, r *http.Request, query url.Values) string { sev := query.Get(apc.QparamLogSev) tempdir, archname, err := h.targzLogs(sev) diff --git a/ais/proxy.go b/ais/proxy.go index aa499c0957..8130afef25 100644 --- a/ais/proxy.go +++ b/ais/proxy.go @@ -21,7 +21,6 @@ import ( "time" "github.com/NVIDIA/aistore/api/apc" - "github.com/NVIDIA/aistore/api/env" "github.com/NVIDIA/aistore/cmn" "github.com/NVIDIA/aistore/cmn/archive" "github.com/NVIDIA/aistore/cmn/atomic" @@ -2450,7 +2449,8 @@ func (p *proxy) httpdaeget(w http.ResponseWriter, r *http.Request) { } fallthrough // fallthrough case apc.WhatNodeConfig, apc.WhatSmapVote, apc.WhatSnode, apc.WhatLog, - apc.WhatNodeStats, apc.WhatMetricNames: + apc.WhatNodeStats, apc.WhatNodeStatsV322, apc.WhatMetricNames, + apc.WhatNodeStatsAndStatus, apc.WhatNodeStatsAndStatusV322: p.htrun.httpdaeget(w, r, query, nil /*htext*/) case apc.WhatSysInfo: p.writeJSON(w, r, apc.GetMemCPU(), what) @@ -2478,24 +2478,6 @@ func (p *proxy) httpdaeget(w http.ResponseWriter, r *http.Request) { return } p.writeJSON(w, r, smap, what) - case apc.WhatNodeStatsAndStatus: - smap := p.owner.smap.get() - msg := &stats.NodeStatus{ - Node: stats.Node{ - Snode: p.htrun.si, - }, - SmapVersion: smap.Version, - MemCPUInfo: apc.GetMemCPU(), - DeploymentType: deploymentType(), - Version: daemon.version, - BuildTime: daemon.buildTime, - K8sPodName: os.Getenv(env.AIS.K8sPod), - Status: p._status(smap), - } - daeStats := p.statsT.GetStats() - msg.Tracker = daeStats.Tracker - - p.writeJSON(w, r, msg, what) default: p.htrun.httpdaeget(w, r, query, nil /*htext*/) } diff --git a/ais/prxclu.go b/ais/prxclu.go index 6da74a08cf..9b88bae9f8 100644 --- a/ais/prxclu.go +++ b/ais/prxclu.go @@ -74,7 +74,7 @@ func (p *proxy) httpcluget(w http.ResponseWriter, r *http.Request) { p.xquery(w, r, what, query) case apc.WhatAllRunningXacts: p.xgetRunning(w, r, what, query) - case apc.WhatNodeStats: + case apc.WhatNodeStats, apc.WhatNodeStatsV322: p.qcluStats(w, r, what, query) case apc.WhatSysInfo: p.qcluSysinfo(w, r, what, query) diff --git a/ais/tgtcp.go b/ais/tgtcp.go index de6352bee8..85f27b8bc3 100644 --- a/ais/tgtcp.go +++ b/ais/tgtcp.go @@ -9,7 +9,6 @@ import ( "fmt" "net/http" "net/url" - "os" "path/filepath" "strconv" "sync" @@ -17,7 +16,6 @@ import ( "github.com/NVIDIA/aistore/ais/backend" "github.com/NVIDIA/aistore/api/apc" - "github.com/NVIDIA/aistore/api/env" "github.com/NVIDIA/aistore/cmn" "github.com/NVIDIA/aistore/cmn/cos" "github.com/NVIDIA/aistore/cmn/debug" @@ -32,7 +30,6 @@ import ( "github.com/NVIDIA/aistore/nl" "github.com/NVIDIA/aistore/reb" "github.com/NVIDIA/aistore/res" - "github.com/NVIDIA/aistore/stats" "github.com/NVIDIA/aistore/xact" "github.com/NVIDIA/aistore/xact/xreg" jsoniter "github.com/json-iterator/go" @@ -287,40 +284,40 @@ func (t *target) httpdaeget(w http.ResponseWriter, r *http.Request) { ) switch getWhat { case apc.WhatNodeConfig, apc.WhatSmap, apc.WhatBMD, apc.WhatSmapVote, - apc.WhatSnode, apc.WhatLog, apc.WhatNodeStats, apc.WhatMetricNames: + apc.WhatSnode, apc.WhatLog, apc.WhatMetricNames: t.htrun.httpdaeget(w, r, query, t /*htext*/) case apc.WhatSysInfo: tsysinfo := apc.TSysInfo{MemCPUInfo: apc.GetMemCPU(), CapacityInfo: fs.CapStatusGetWhat()} t.writeJSON(w, r, tsysinfo, httpdaeWhat) case apc.WhatMountpaths: t.writeJSON(w, r, fs.MountpathsToLists(), httpdaeWhat) + + case apc.WhatNodeStats: + ds := t.statsAndStatus() + daeStats := t.statsT.GetStats() + ds.Tracker = daeStats.Tracker + t.writeJSON(w, r, ds, httpdaeWhat) + case apc.WhatNodeStatsV322: // [backward compatibility] v3.22 and prior + ds := t.statsAndStatusV322() + daeStats := t.statsT.GetStatsV322() + ds.Tracker = daeStats.Tracker + t.writeJSON(w, r, ds, httpdaeWhat) case apc.WhatNodeStatsAndStatus: - var rebSnap *core.Snap - if entry := xreg.GetLatest(xreg.Flt{Kind: apc.ActRebalance}); entry != nil { - if xctn := entry.Get(); xctn != nil { - rebSnap = xctn.Snap() - } - } - smap := t.owner.smap.get() - msg := &stats.NodeStatus{ - Node: stats.Node{ - Snode: t.htrun.si, - }, - SmapVersion: smap.Version, - MemCPUInfo: apc.GetMemCPU(), - RebSnap: rebSnap, - DeploymentType: deploymentType(), - Version: daemon.version, - BuildTime: daemon.buildTime, - K8sPodName: os.Getenv(env.AIS.K8sPod), - Status: t._status(smap), - } - // stats and capacity + ds := t.statsAndStatus() + ds.RebSnap = _rebSnap() daeStats := t.statsT.GetStats() - msg.Tracker = daeStats.Tracker - msg.TargetCDF = daeStats.TargetCDF + ds.Tracker = daeStats.Tracker + ds.TargetCDF = daeStats.TargetCDF + nlog.Errorln(ds.TargetCDF.TotalUsed, ds.TargetCDF.TotalAvail) // DEBUG + t.writeJSON(w, r, ds, httpdaeWhat) + case apc.WhatNodeStatsAndStatusV322: // [ditto] + ds := t.statsAndStatusV322() + ds.RebSnap = _rebSnap() + daeStats := t.statsT.GetStatsV322() + ds.Tracker = daeStats.Tracker + ds.TargetCDF = daeStats.TargetCDF + t.writeJSON(w, r, ds, httpdaeWhat) - t.writeJSON(w, r, msg, httpdaeWhat) case apc.WhatDiskStats: diskStats := make(ios.AllDiskStats) fs.FillDiskStats(diskStats) @@ -349,6 +346,15 @@ func (t *target) httpdaeget(w http.ResponseWriter, r *http.Request) { } } +func _rebSnap() (rebSnap *core.Snap) { + if entry := xreg.GetLatest(xreg.Flt{Kind: apc.ActRebalance}); entry != nil { + if xctn := entry.Get(); xctn != nil { + rebSnap = xctn.Snap() + } + } + return rebSnap +} + // admin-join target | enable/disable mountpath func (t *target) httpdaepost(w http.ResponseWriter, r *http.Request) { apiItems, err := t.parseURL(w, r, apc.URLPathDae.L, 0, true) diff --git a/api/apc/query.go b/api/apc/query.go index b40fe83ab0..c6d2f01196 100644 --- a/api/apc/query.go +++ b/api/apc/query.go @@ -184,11 +184,15 @@ const ( // config WhatNodeConfig = "config" // query specific node for (cluster config + overrides, local config) WhatClusterConfig = "cluster_config" - // stats - WhatNodeStats = "stats" - WhatNodeStatsAndStatus = "status" - WhatMetricNames = "metrics" - WhatDiskStats = "disk" + + // stats and status + WhatNodeStatsV322 = "stats" // [ backward compatibility ] + WhatNodeStatsAndStatusV322 = "status" // [ ditto ] + WhatNodeStats = "node_stats" + WhatNodeStatsAndStatus = "node_status" + + WhatMetricNames = "metrics" + WhatDiskStats = "disk" // assorted WhatMountpaths = "mountpaths" WhatRemoteAIS = "remote" diff --git a/api/blob.go b/api/blob.go index bc72678b20..9d8465fa62 100644 --- a/api/blob.go +++ b/api/blob.go @@ -1,4 +1,4 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* * Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. */ diff --git a/api/bsumm.go b/api/bsumm.go index 7d864cf5f0..255bab3c9b 100644 --- a/api/bsumm.go +++ b/api/bsumm.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api diff --git a/api/bucket.go b/api/bucket.go index 3b09c86d63..fd4d4f243d 100644 --- a/api/bucket.go +++ b/api/bucket.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api diff --git a/api/client.go b/api/client.go index ec6f6f71b3..51e1a2fae5 100644 --- a/api/client.go +++ b/api/client.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api diff --git a/api/cluster.go b/api/cluster.go index fb6107f89b..22093922c7 100644 --- a/api/cluster.go +++ b/api/cluster.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api @@ -13,8 +13,6 @@ import ( "github.com/NVIDIA/aistore/cmn" "github.com/NVIDIA/aistore/cmn/cos" "github.com/NVIDIA/aistore/core/meta" - "github.com/NVIDIA/aistore/stats" - jsoniter "github.com/json-iterator/go" ) // to be used by external watchdogs (Kubernetes, etc.) @@ -158,46 +156,6 @@ func GetClusterSysInfo(bp BaseParams) (info apc.ClusterSysInfo, err error) { return } -// How to compute throughputs: -// -// - AIS supports several enumerated metric "kinds", including `KindThroughput` -// (for complete enumeration, see stats/api.go) -// - By convention, metrics that have `KindThroughput` kind are named with ".bps" -// ("bytes per second") suffix. -// - ".bps" metrics reported by api.GetClusterStats and api.GetDaemonStats are, -// in fact, cumulative byte numbers. -// - It is the client's responsibility to compute the actual throughputs -// as only the client knows _when_ exactly the same ".bps" metric was queried -// the previous time. -// -// - See also: `api.GetDaemonStats`, stats/api.go -func GetClusterStats(bp BaseParams) (res stats.Cluster, err error) { - bp.Method = http.MethodGet - reqParams := AllocRp() - { - reqParams.BaseParams = bp - reqParams.Path = apc.URLPathClu.S - reqParams.Query = url.Values{apc.QparamWhat: []string{apc.WhatNodeStats}} - } - - var rawStats stats.ClusterRaw - _, err = reqParams.DoReqAny(&rawStats) - FreeRp(reqParams) - if err != nil { - return - } - - res.Proxy = rawStats.Proxy - res.Target = make(map[string]*stats.Node) - for tid := range rawStats.Target { - var ts stats.Node - if err := jsoniter.Unmarshal(rawStats.Target[tid], &ts); err == nil { - res.Target[tid] = &ts - } - } - return -} - func GetRemoteAIS(bp BaseParams) (remais meta.RemAisVec, err error) { bp.Method = http.MethodGet reqParams := AllocRp() @@ -290,11 +248,6 @@ func SetClusterConfigUsingMsg(bp BaseParams, configToUpdate *cmn.ConfigToSet, tr return err } -// zero out: all metrics _or_ only error counters -func ResetClusterStats(bp BaseParams, errorsOnly bool) (err error) { - return _putCluster(bp, apc.ActMsg{Action: apc.ActResetStats, Value: errorsOnly}) -} - // all nodes: reset configuration to cluster defaults func ResetClusterConfig(bp BaseParams) error { return _putCluster(bp, apc.ActMsg{Action: apc.ActResetConfig}) diff --git a/api/daemon.go b/api/daemon.go index 97cdab9d4c..044bba2b47 100644 --- a/api/daemon.go +++ b/api/daemon.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api @@ -15,7 +15,6 @@ import ( "github.com/NVIDIA/aistore/cmn/cos" "github.com/NVIDIA/aistore/core/meta" "github.com/NVIDIA/aistore/ios" - "github.com/NVIDIA/aistore/stats" ) type GetLogInput struct { @@ -167,64 +166,6 @@ func GetMetricNames(bp BaseParams, node *meta.Snode) (kvs cos.StrKVs, err error) return } -// How to compute throughputs: -// -// - AIS supports several enumerated metric "kinds", including `KindThroughput` -// (for complete enumeration, see stats/api.go) -// - By convention, metrics that have `KindThroughput` kind are named with ".bps" -// ("bytes per second") suffix. -// - ".bps" metrics reported by the API are, in fact, cumulative byte numbers. -// - It is the client's responsibility to compute the actual throughputs -// as only the client knows _when_ exactly the same ".bps" metric was queried -// the previous time. -// -// See also: -// - api.GetClusterStats -// - api.GetStatsAndStatus (below) -// - stats/api.go -func GetDaemonStats(bp BaseParams, node *meta.Snode) (ds *stats.Node, err error) { - bp.Method = http.MethodGet - reqParams := AllocRp() - { - reqParams.BaseParams = bp - reqParams.Path = apc.URLPathReverseDae.S - reqParams.Query = url.Values{apc.QparamWhat: []string{apc.WhatNodeStats}} - reqParams.Header = http.Header{apc.HdrNodeID: []string{node.ID()}} - } - _, err = reqParams.DoReqAny(&ds) - FreeRp(reqParams) - return ds, err -} - -func GetDiskStats(bp BaseParams, tid string) (res ios.AllDiskStats, err error) { - bp.Method = http.MethodGet - reqParams := AllocRp() - { - reqParams.BaseParams = bp - reqParams.Path = apc.URLPathReverseDae.S - reqParams.Query = url.Values{apc.QparamWhat: []string{apc.WhatDiskStats}} - reqParams.Header = http.Header{apc.HdrNodeID: []string{tid}} - } - _, err = reqParams.DoReqAny(&res) - FreeRp(reqParams) - return -} - -// Returns both node's stats and extended status -func GetStatsAndStatus(bp BaseParams, node *meta.Snode) (daeStatus *stats.NodeStatus, err error) { - bp.Method = http.MethodGet - reqParams := AllocRp() - { - reqParams.BaseParams = bp - reqParams.Path = apc.URLPathReverseDae.S - reqParams.Query = url.Values{apc.QparamWhat: []string{apc.WhatNodeStatsAndStatus}} - reqParams.Header = http.Header{apc.HdrNodeID: []string{node.ID()}} - } - _, err = reqParams.DoReqAny(&daeStatus) - FreeRp(reqParams) - return daeStatus, err -} - // Returns log of a specific node in a cluster. func GetDaemonLog(bp BaseParams, node *meta.Snode, args GetLogInput) (int64, error) { w := args.Writer @@ -277,11 +218,6 @@ func SetDaemonConfig(bp BaseParams, nodeID string, nvs cos.StrKVs, transient ... return err } -// see also: ResetClusterStats -func ResetDaemonStats(bp BaseParams, node *meta.Snode, errorsOnly bool) error { - return _putDaemon(bp, node.ID(), apc.ActMsg{Action: apc.ActResetStats, Value: errorsOnly}) -} - // reset node's configuration to cluster defaults func ResetDaemonConfig(bp BaseParams, nodeID string) error { return _putDaemon(bp, nodeID, apc.ActMsg{Action: apc.ActResetConfig}) diff --git a/api/download.go b/api/download.go index ef3c1bbe9c..0f88fd5e83 100644 --- a/api/download.go +++ b/api/download.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api diff --git a/api/dsort.go b/api/dsort.go index f48a281b25..f71402bba9 100644 --- a/api/dsort.go +++ b/api/dsort.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api diff --git a/api/etl.go b/api/etl.go index 443cacc05c..8ccf813572 100644 --- a/api/etl.go +++ b/api/etl.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api diff --git a/api/ls.go b/api/ls.go index e1866582d3..384cdff9bd 100644 --- a/api/ls.go +++ b/api/ls.go @@ -1,4 +1,4 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ diff --git a/api/multiobj.go b/api/multiobj.go index d685b724f3..65418f37c4 100644 --- a/api/multiobj.go +++ b/api/multiobj.go @@ -1,4 +1,4 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ diff --git a/api/object.go b/api/object.go index 3d9eccfe36..6c6fdfb055 100644 --- a/api/object.go +++ b/api/object.go @@ -1,4 +1,4 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ diff --git a/api/s3.go b/api/s3.go index bf466dc532..075f56d7a4 100644 --- a/api/s3.go +++ b/api/s3.go @@ -1,6 +1,6 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package api diff --git a/api/stats.go b/api/stats.go new file mode 100644 index 0000000000..4700b29023 --- /dev/null +++ b/api/stats.go @@ -0,0 +1,109 @@ +// Package api provides native Go-based API/SDK over HTTP(S). +/* + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. + */ +package api + +import ( + "net/http" + "net/url" + + "github.com/NVIDIA/aistore/api/apc" + "github.com/NVIDIA/aistore/core/meta" + "github.com/NVIDIA/aistore/ios" + "github.com/NVIDIA/aistore/stats" + jsoniter "github.com/json-iterator/go" +) + +// How to compute throughputs: +// +// - AIS supports several enumerated "kinds" of metrics (for complete enum, see stats/api.go). +// - By convention, metrics that have `KindThroughput` kind are named with ".bps" ("bytes per second") suffix. +// - ".bps" metrics reported by api.GetClusterStats and api.GetDaemonStats are, in fact, cumulative byte numbers. +// - It is the client's responsibility to compute the actual throughputs as only the client knows _when_ exactly +// the same ".bps" metric was queried the previous time. +// +// See also: +// - api.GetClusterStats +// - api.GetDaemonStats +// - api.GetStatsAndStatus +// - stats/api.go + +// +// cluster ---------------------- +// + +func GetClusterStats(bp BaseParams) (res stats.Cluster, err error) { + bp.Method = http.MethodGet + reqParams := AllocRp() + { + reqParams.BaseParams = bp + reqParams.Path = apc.URLPathClu.S + reqParams.Query = url.Values{apc.QparamWhat: []string{apc.WhatNodeStats}} + } + + var rawStats stats.ClusterRaw + _, err = reqParams.DoReqAny(&rawStats) + FreeRp(reqParams) + if err != nil { + return + } + + res.Proxy = rawStats.Proxy + res.Target = make(map[string]*stats.Node, len(rawStats.Target)) + for tid := range rawStats.Target { + var ts stats.Node + if err := jsoniter.Unmarshal(rawStats.Target[tid], &ts); err == nil { + res.Target[tid] = &ts + } + } + return +} + +// +// node ---------------------- +// + +func anyStats(bp BaseParams, sid, what string, out any) (err error) { + bp.Method = http.MethodGet + reqParams := AllocRp() + { + reqParams.BaseParams = bp + reqParams.Path = apc.URLPathReverseDae.S + reqParams.Query = url.Values{apc.QparamWhat: []string{what}} + reqParams.Header = http.Header{apc.HdrNodeID: []string{sid}} + } + _, err = reqParams.DoReqAny(out) + FreeRp(reqParams) + return err +} + +func GetDaemonStats(bp BaseParams, node *meta.Snode) (ds *stats.Node, err error) { + ds = &stats.Node{} + err = anyStats(bp, node.ID(), apc.WhatNodeStats, ds) + return ds, err +} + +// returns both node's stats (as above) and extended status +func GetStatsAndStatus(bp BaseParams, node *meta.Snode) (ds *stats.NodeStatus, err error) { + ds = &stats.NodeStatus{} + err = anyStats(bp, node.ID(), apc.WhatNodeStatsAndStatus, ds) + return ds, err +} + +func GetDiskStats(bp BaseParams, tid string) (res ios.AllDiskStats, err error) { + err = anyStats(bp, tid, apc.WhatDiskStats, &res) + return res, err +} + +// +// reset (cluster | node) stats _or_ only error counters ------------ +// + +func ResetClusterStats(bp BaseParams, errorsOnly bool) (err error) { + return _putCluster(bp, apc.ActMsg{Action: apc.ActResetStats, Value: errorsOnly}) +} + +func ResetDaemonStats(bp BaseParams, node *meta.Snode, errorsOnly bool) error { + return _putDaemon(bp, node.ID(), apc.ActMsg{Action: apc.ActResetStats, Value: errorsOnly}) +} diff --git a/api/xaction.go b/api/xaction.go index c506bc1186..af042d042c 100644 --- a/api/xaction.go +++ b/api/xaction.go @@ -1,4 +1,4 @@ -// Package api provides Go based AIStore API/SDK over HTTP(S) +// Package api provides native Go-based API/SDK over HTTP(S). /* * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ diff --git a/cmd/cli/go.mod b/cmd/cli/go.mod index f097c6738d..a808142567 100644 --- a/cmd/cli/go.mod +++ b/cmd/cli/go.mod @@ -3,7 +3,7 @@ module github.com/NVIDIA/aistore/cmd/cli go 1.22 require ( - github.com/NVIDIA/aistore v1.3.23-0.20240323000353-33061aec490d + github.com/NVIDIA/aistore v1.3.23-0.20240324173820-740ea3dc794e github.com/fatih/color v1.16.0 github.com/json-iterator/go v1.1.12 github.com/onsi/ginkgo v1.16.5 diff --git a/cmd/cli/go.sum b/cmd/cli/go.sum index d85a4d98fe..d3a6e9591c 100644 --- a/cmd/cli/go.sum +++ b/cmd/cli/go.sum @@ -1,7 +1,7 @@ code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/NVIDIA/aistore v1.3.23-0.20240323000353-33061aec490d h1:vtkEeH8Jls/lvQ7OhewpjlOUfH6K1xTL2iodpgpMcqM= -github.com/NVIDIA/aistore v1.3.23-0.20240323000353-33061aec490d/go.mod h1:3UqMJIK/9VMRalJNIRvz7amtXLLOmIGWy5mV8l5tbiE= +github.com/NVIDIA/aistore v1.3.23-0.20240324173820-740ea3dc794e h1:vchlijEP/kZpDAuxAT1sJt/TOxvYR6f2qwmKsWDwNNQ= +github.com/NVIDIA/aistore v1.3.23-0.20240324173820-740ea3dc794e/go.mod h1:3UqMJIK/9VMRalJNIRvz7amtXLLOmIGWy5mV8l5tbiE= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= diff --git a/cmn/config.go b/cmn/config.go index 5c1593a311..e1b1d2d273 100644 --- a/cmn/config.go +++ b/cmn/config.go @@ -73,12 +73,12 @@ type ( UseIntraData bool `json:"-"` } - // ais node: fspaths (a.k.a. mountpaths) + // ais node: fspaths (a.k.a. mountpaths) and their respective (optional) labels FSPConf struct { Paths cos.StrKVs `json:"paths,omitempty" list:"readonly"` } - // NOTE: keeping V3 meta-version for backward compatibility - FSPConfV3 struct { + // [backward compatibility]: v3.22 and prior + FSPConfV322 struct { Paths cos.StrSet `json:"paths,omitempty" list:"readonly"` } @@ -1396,11 +1396,11 @@ func (c *FSPConf) UnmarshalJSON(data []byte) error { c.Paths = m return nil } - // load from the prev. meta-version (backward compatibility) - var v3 FSPConfV3 - v3.Paths = make(cos.StrSet, 10) - if err = jsoniter.Unmarshal(data, &v3.Paths); err == nil { - for fspath := range v3.Paths { + // [backward compatibility] try loading from the prev. meta-version + var v322 FSPConfV322 + v322.Paths = make(cos.StrSet, 10) + if err = jsoniter.Unmarshal(data, &v322.Paths); err == nil { + for fspath := range v322.Paths { m[fspath] = "" } c.Paths = m diff --git a/cmn/ver_const.go b/cmn/ver_const.go index 29f1914016..d3ec349845 100644 --- a/cmn/ver_const.go +++ b/cmn/ver_const.go @@ -27,7 +27,7 @@ const GitHubHome = "https://github.com/NVIDIA/aistore" const ( VersionAIStore = "3.22" - VersionCLI = "1.10" + VersionCLI = "1.12" VersionLoader = "1.10" VersionAuthN = "1.0" ) diff --git a/core/mock/stats_mock.go b/core/mock/stats_mock.go index 5739f142d4..dc17cdd9ad 100644 --- a/core/mock/stats_mock.go +++ b/core/mock/stats_mock.go @@ -21,14 +21,15 @@ func NewStatsTracker() stats.Tracker { return &StatsTracker{} } -func (*StatsTracker) StartedUp() bool { return true } -func (*StatsTracker) Get(string) int64 { return 0 } -func (*StatsTracker) IncErr(string) {} -func (*StatsTracker) Inc(string) {} -func (*StatsTracker) Add(string, int64) {} -func (*StatsTracker) AddMany(...cos.NamedVal64) {} -func (*StatsTracker) RegMetrics(*meta.Snode) {} -func (*StatsTracker) GetMetricNames() cos.StrKVs { return nil } -func (*StatsTracker) GetStats() *stats.Node { return nil } -func (*StatsTracker) ResetStats(bool) {} -func (*StatsTracker) IsPrometheus() bool { return false } +func (*StatsTracker) StartedUp() bool { return true } +func (*StatsTracker) Get(string) int64 { return 0 } +func (*StatsTracker) IncErr(string) {} +func (*StatsTracker) Inc(string) {} +func (*StatsTracker) Add(string, int64) {} +func (*StatsTracker) AddMany(...cos.NamedVal64) {} +func (*StatsTracker) RegMetrics(*meta.Snode) {} +func (*StatsTracker) GetMetricNames() cos.StrKVs { return nil } +func (*StatsTracker) GetStats() *stats.Node { return nil } +func (*StatsTracker) GetStatsV322() *stats.NodeV322 { return nil } +func (*StatsTracker) ResetStats(bool) {} +func (*StatsTracker) IsPrometheus() bool { return false } diff --git a/fs/api.go b/fs/api.go index 564993acca..e8b653fa64 100644 --- a/fs/api.go +++ b/fs/api.go @@ -34,6 +34,22 @@ type ( } ) +// [backward compatibility]: v3.22 cdf* structures +type ( + CDFv322 struct { + Capacity + Disks []string `json:"disks"` + FS string `json:"fs"` + } + TargetCDFv322 struct { + Mountpaths map[string]*CDFv322 + PctMax int32 `json:"pct_max"` + PctAvg int32 `json:"pct_avg"` + PctMin int32 `json:"pct_min"` + CsErr string `json:"cs_err"` + } +) + func InitCDF(tcdf *TargetCDF) { avail := GetAvail() tcdf.Mountpaths = make(map[string]*CDF, len(avail)) diff --git a/stats/api.go b/stats/api.go index 274130de13..2a244d90ed 100644 --- a/stats/api.go +++ b/stats/api.go @@ -40,6 +40,8 @@ type ( IncErr(metric string) GetStats() *Node + GetStatsV322() *NodeV322 // [backward compatibility] + ResetStats(errorsOnly bool) GetMetricNames() cos.StrKVs // (name, kind) pairs @@ -76,6 +78,27 @@ type ( } ) +// [backward compatibility]: includes v3.22 cdf* structures +type ( + NodeV322 struct { + Snode *meta.Snode `json:"snode"` + Tracker copyTracker `json:"tracker"` + TargetCDF fs.TargetCDFv322 `json:"capacity"` + } + NodeStatusV322 struct { + NodeV322 + RebSnap *core.Snap `json:"rebalance_snap,omitempty"` + // assorted props + Status string `json:"status"` + DeploymentType string `json:"deployment"` + Version string `json:"ais_version"` // major.minor.build + BuildTime string `json:"build_time"` // YYYY-MM-DD HH:MM:SS-TZ + K8sPodName string `json:"k8s_pod_name"` // (via ais-k8s/operator `MY_POD` env var) + MemCPUInfo apc.MemCPUInfo `json:"sys_info"` + SmapVersion int64 `json:"smap_version,string"` + } +) + func IsErrMetric(name string) bool { return strings.HasPrefix(name, errPrefix) // e.g. name = ErrHTTPWriteCount } diff --git a/stats/common_stats.go b/stats/common_stats.go index ae11d71a0e..8d88f542db 100644 --- a/stats/common_stats.go +++ b/stats/common_stats.go @@ -586,6 +586,15 @@ func (r *runner) GetStats() *Node { return &Node{Tracker: ctracker} } +func (r *runner) GetStatsV322() (out *NodeV322) { + ds := r.GetStats() + + out = &NodeV322{} + out.Snode = ds.Snode + out.Tracker = ds.Tracker + return out +} + func (r *runner) ResetStats(errorsOnly bool) { r.core.reset(errorsOnly) } diff --git a/stats/target_stats.go b/stats/target_stats.go index 3b41f2c61e..99784a6852 100644 --- a/stats/target_stats.go +++ b/stats/target_stats.go @@ -290,7 +290,30 @@ func (r *Trunner) GetStats() (ds *Node) { fs.InitCDF(&ds.TargetCDF) fs.CapRefresh(nil, &ds.TargetCDF) - return + return ds +} + +// [backward compatibility] v3.22 and prior +func (r *Trunner) GetStatsV322() (out *NodeV322) { + ds := r.GetStats() + + out = &NodeV322{} + out.Snode = ds.Snode + out.Tracker = ds.Tracker + out.TargetCDF.PctMax = ds.TargetCDF.PctMax + out.TargetCDF.PctAvg = ds.TargetCDF.PctAvg + out.TargetCDF.PctMin = ds.TargetCDF.PctMin + out.TargetCDF.CsErr = ds.TargetCDF.CsErr + out.TargetCDF.Mountpaths = make(map[string]*fs.CDFv322, len(ds.TargetCDF.Mountpaths)) + for mpath := range ds.TargetCDF.Mountpaths { + cdf := &fs.CDFv322{ + Capacity: ds.TargetCDF.Mountpaths[mpath].Capacity, + Disks: ds.TargetCDF.Mountpaths[mpath].Disks, + FS: ds.TargetCDF.Mountpaths[mpath].FS.String(), + } + out.TargetCDF.Mountpaths[mpath] = cdf + } + return out } func (r *Trunner) log(now int64, uptime time.Duration, config *cmn.Config) {