Skip to content

Commit

Permalink
feat: upgrade ZAPI conversations to REST when ZAPIs are suspended or … (
Browse files Browse the repository at this point in the history
#2200)

* feat: upgrade ZAPI conversations to REST when ZAPIs are suspended or disabled

* feat: error handling changes

---------

Co-authored-by: Rahul Gupta <[email protected]>
  • Loading branch information
cgrinds and rahulguptajss authored Jul 11, 2023
1 parent e3b2910 commit e5c6d40
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 19 deletions.
37 changes: 27 additions & 10 deletions cmd/poller/poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import (
"github.com/netapp/harvest/v2/pkg/matrix"
"github.com/netapp/harvest/v2/pkg/tree/node"
"github.com/netapp/harvest/v2/pkg/util"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
"io"
Expand Down Expand Up @@ -1129,11 +1130,10 @@ func (p *Poller) createClient() {

// upgradeCollector checks if the collector c should be upgraded to a REST collector.
// ZAPI collectors should be upgraded to REST collectors when the cluster no longer speaks Zapi
// If any error happens during the REST query, the upgrade is aborted and the original collector c returned.
func (p *Poller) upgradeCollector(c conf.Collector) conf.Collector {
// If REST is desired, use REST
// If ZAPI is desired, check that the cluster speaks ZAPI and if so, use ZAPI otherwise use REST
// EMS and StorageGRID are will be ignored
// If ZAPI is desired, check that the cluster speaks ZAPI and if so, use ZAPI, otherwise use REST
// EMS and StorageGRID are ignored

if !strings.HasPrefix(c.Name, "Zapi") {
return c
Expand All @@ -1142,17 +1142,34 @@ func (p *Poller) upgradeCollector(c conf.Collector) conf.Collector {
return p.negotiateAPI(c, p.doZAPIsExist)
}

// clusterVersion should be of the form 9.12.1
// Harvest will upgrade ZAPI conversations to REST in two cases:
// - if ONTAP returns a ZAPI error with errno=61253
// - if ONTAP returns an HTTP status code of 400
func (p *Poller) negotiateAPI(c conf.Collector, checkZAPIs func() error) conf.Collector {
var switchToRest bool
err := checkZAPIs()
// if there is an error talking to ONTAP, assume that is because ZAPIs no longer exist and use REST

if err != nil {
logger.Warn().Err(err).Str("collector", c.Name).Msg("ZAPI EOA. Use REST")
upgradeCollector := strings.ReplaceAll(c.Name, "Zapi", "Rest")
return conf.Collector{
Name: upgradeCollector,
Templates: c.Templates,
var he errs.HarvestError
if errors.As(err, &he) {
if he.ErrNum == errs.ErrNumZAPISuspended {
logger.Warn().Str("collector", c.Name).Msg("ZAPIs suspended. Use REST")
switchToRest = true
}

if he.StatusCode == 400 {
logger.Warn().Str("collector", c.Name).Msg("ZAPIs EOA. Use REST")
switchToRest = true
}
}
if switchToRest {
upgradeCollector := strings.ReplaceAll(c.Name, "Zapi", "Rest")
return conf.Collector{
Name: upgradeCollector,
Templates: c.Templates,
}
}
log.Error().Err(err).Str("collector", c.Name).Msg("Failed to negotiateAPI")
}

return c
Expand Down
11 changes: 7 additions & 4 deletions pkg/api/ontapi/zapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,9 @@ func (c *Client) invoke(withTimers bool) (*node.Node, time.Duration, time.Durati
start time.Time
responseT, parseT time.Duration
body []byte
status, reason string
status string
reason string
errNum string
found bool
err error
)
Expand Down Expand Up @@ -545,9 +547,9 @@ func (c *Client) invoke(withTimers bool) (*node.Node, time.Duration, time.Durati

if response.StatusCode != 200 {
if response.StatusCode == 401 {
return result, responseT, parseT, errs.New(errs.ErrAuthFailed, response.Status)
return result, responseT, parseT, errs.New(errs.ErrAuthFailed, response.Status, errs.WithStatus(response.StatusCode))
}
return result, responseT, parseT, errs.New(errs.ErrAPIResponse, response.Status)
return result, responseT, parseT, errs.New(errs.ErrAPIResponse, response.Status, errs.WithStatus(response.StatusCode))
}

// read response body
Expand Down Expand Up @@ -581,7 +583,8 @@ func (c *Client) invoke(withTimers bool) (*node.Node, time.Duration, time.Durati
if reason == "" {
reason = "no reason"
}
err = errs.New(errs.ErrAPIRequestRejected, reason)
errNum, _ = result.GetAttrValueS("errno")
err = errs.New(errs.ErrAPIRequestRejected, reason, errs.WithErrorNum(errNum))
return result, responseT, parseT, err
}

Expand Down
37 changes: 32 additions & 5 deletions pkg/errs/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,29 @@ const (
ErrWrongTemplate = harvestError("wrong template")
)

const (
ErrNumZAPISuspended = "61253"
)

type HarvestError struct {
Message string
Inner error
Message string
Inner error
ErrNum string
StatusCode int
}

type Option func(*HarvestError)

func WithStatus(statusCode int) Option {
return func(e *HarvestError) {
e.StatusCode = statusCode
}
}

func WithErrorNum(errNum string) Option {
return func(e *HarvestError) {
e.ErrNum = errNum
}
}

func (e HarvestError) Error() string {
Expand All @@ -43,13 +63,20 @@ func (e HarvestError) Error() string {
if e.Message == "" {
return e.Inner.Error()
}
return fmt.Sprintf("%s => %s", e.Inner.Error(), e.Message)
if e.ErrNum == "" && e.StatusCode == 0 {
return fmt.Sprintf("%s => %s", e.Inner.Error(), e.Message)
}
return fmt.Sprintf(`%s => %s errNum="%s" statusCode="%d"`, e.Inner.Error(), e.Message, e.ErrNum, e.StatusCode)
}

func (e HarvestError) Unwrap() error {
return e.Inner
}

func New(err error, message string) error {
return HarvestError{Message: message, Inner: err}
func New(innerError error, message string, opts ...Option) error {
err := HarvestError{Message: message, Inner: innerError}
for _, opt := range opts {
opt(&err)
}
return err
}

0 comments on commit e5c6d40

Please sign in to comment.