github.com/hernad/nomad@v1.6.112/nomad/structs/errors.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package structs
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"strconv"
    10  	"strings"
    11  )
    12  
    13  const (
    14  	errNoLeader                   = "No cluster leader"
    15  	errNotReadyForConsistentReads = "Not ready to serve consistent reads"
    16  	errNoRegionPath               = "No path to region"
    17  	errTokenNotFound              = "ACL token not found"
    18  	errTokenExpired               = "ACL token expired"
    19  	errTokenInvalid               = "ACL token is invalid" // not a UUID
    20  	errPermissionDenied           = "Permission denied"
    21  	errJobRegistrationDisabled    = "Job registration, dispatch, and scale are disabled by the scheduler configuration"
    22  	errNoNodeConn                 = "No path to node"
    23  	errUnknownMethod              = "Unknown rpc method"
    24  	errUnknownNomadVersion        = "Unable to determine Nomad version"
    25  	errNodeLacksRpc               = "Node does not support RPC; requires 0.8 or later"
    26  	errMissingAllocID             = "Missing allocation ID"
    27  	errIncompatibleFiltering      = "Filter expression cannot be used with other filter parameters"
    28  	errMalformedChooseParameter   = "Parameter for choose must be in form '<number>|<key>'"
    29  
    30  	// Prefix based errors that are used to check if the error is of a given
    31  	// type. These errors should be created with the associated constructor.
    32  	ErrUnknownAllocationPrefix = "Unknown allocation"
    33  	ErrUnknownNodePrefix       = "Unknown node"
    34  	ErrUnknownJobPrefix        = "Unknown job"
    35  	ErrUnknownEvaluationPrefix = "Unknown evaluation"
    36  	ErrUnknownDeploymentPrefix = "Unknown deployment"
    37  
    38  	errRPCCodedErrorPrefix = "RPC Error:: "
    39  
    40  	errDeploymentTerminalNoCancel    = "can't cancel terminal deployment"
    41  	errDeploymentTerminalNoFail      = "can't fail terminal deployment"
    42  	errDeploymentTerminalNoPause     = "can't pause terminal deployment"
    43  	errDeploymentTerminalNoPromote   = "can't promote terminal deployment"
    44  	errDeploymentTerminalNoResume    = "can't resume terminal deployment"
    45  	errDeploymentTerminalNoUnblock   = "can't unblock terminal deployment"
    46  	errDeploymentTerminalNoRun       = "can't run terminal deployment"
    47  	errDeploymentTerminalNoSetHealth = "can't set health of allocations for a terminal deployment"
    48  	errDeploymentRunningNoUnblock    = "can't unblock running deployment"
    49  )
    50  
    51  var (
    52  	ErrNoLeader                   = errors.New(errNoLeader)
    53  	ErrNotReadyForConsistentReads = errors.New(errNotReadyForConsistentReads)
    54  	ErrNoRegionPath               = errors.New(errNoRegionPath)
    55  	ErrTokenNotFound              = errors.New(errTokenNotFound)
    56  	ErrTokenExpired               = errors.New(errTokenExpired)
    57  	ErrTokenInvalid               = errors.New(errTokenInvalid)
    58  	ErrPermissionDenied           = errors.New(errPermissionDenied)
    59  	ErrJobRegistrationDisabled    = errors.New(errJobRegistrationDisabled)
    60  	ErrNoNodeConn                 = errors.New(errNoNodeConn)
    61  	ErrUnknownMethod              = errors.New(errUnknownMethod)
    62  	ErrUnknownNomadVersion        = errors.New(errUnknownNomadVersion)
    63  	ErrNodeLacksRpc               = errors.New(errNodeLacksRpc)
    64  	ErrMissingAllocID             = errors.New(errMissingAllocID)
    65  	ErrIncompatibleFiltering      = errors.New(errIncompatibleFiltering)
    66  	ErrMalformedChooseParameter   = errors.New(errMalformedChooseParameter)
    67  
    68  	ErrUnknownNode = errors.New(ErrUnknownNodePrefix)
    69  
    70  	ErrDeploymentTerminalNoCancel    = errors.New(errDeploymentTerminalNoCancel)
    71  	ErrDeploymentTerminalNoFail      = errors.New(errDeploymentTerminalNoFail)
    72  	ErrDeploymentTerminalNoPause     = errors.New(errDeploymentTerminalNoPause)
    73  	ErrDeploymentTerminalNoPromote   = errors.New(errDeploymentTerminalNoPromote)
    74  	ErrDeploymentTerminalNoResume    = errors.New(errDeploymentTerminalNoResume)
    75  	ErrDeploymentTerminalNoUnblock   = errors.New(errDeploymentTerminalNoUnblock)
    76  	ErrDeploymentTerminalNoRun       = errors.New(errDeploymentTerminalNoRun)
    77  	ErrDeploymentTerminalNoSetHealth = errors.New(errDeploymentTerminalNoSetHealth)
    78  	ErrDeploymentRunningNoUnblock    = errors.New(errDeploymentRunningNoUnblock)
    79  
    80  	ErrCSIClientRPCIgnorable  = errors.New("CSI client error (ignorable)")
    81  	ErrCSIClientRPCRetryable  = errors.New("CSI client error (retryable)")
    82  	ErrCSIVolumeMaxClaims     = errors.New("volume max claims reached")
    83  	ErrCSIVolumeUnschedulable = errors.New("volume is currently unschedulable")
    84  )
    85  
    86  // IsErrNoLeader returns whether the error is due to there being no leader.
    87  func IsErrNoLeader(err error) bool {
    88  	return err != nil && strings.Contains(err.Error(), errNoLeader)
    89  }
    90  
    91  // IsErrNoRegionPath returns whether the error is due to there being no path to
    92  // the given region.
    93  func IsErrNoRegionPath(err error) bool {
    94  	return err != nil && strings.Contains(err.Error(), errNoRegionPath)
    95  }
    96  
    97  // IsErrTokenNotFound returns whether the error is due to the passed token not
    98  // being resolvable.
    99  func IsErrTokenNotFound(err error) bool {
   100  	return err != nil && strings.Contains(err.Error(), errTokenNotFound)
   101  }
   102  
   103  // IsErrPermissionDenied returns whether the error is due to the operation not
   104  // being allowed due to lack of permissions.
   105  func IsErrPermissionDenied(err error) bool {
   106  	return err != nil && strings.Contains(err.Error(), errPermissionDenied)
   107  }
   108  
   109  // IsErrNoNodeConn returns whether the error is due to there being no path to
   110  // the given node.
   111  func IsErrNoNodeConn(err error) bool {
   112  	return err != nil && strings.Contains(err.Error(), errNoNodeConn)
   113  }
   114  
   115  // IsErrUnknownMethod returns whether the error is due to the operation not
   116  // being allowed due to lack of permissions.
   117  func IsErrUnknownMethod(err error) bool {
   118  	return err != nil && strings.Contains(err.Error(), errUnknownMethod)
   119  }
   120  
   121  func IsErrRPCCoded(err error) bool {
   122  	return err != nil && strings.HasPrefix(err.Error(), errRPCCodedErrorPrefix)
   123  }
   124  
   125  // NewErrUnknownAllocation returns a new error caused by the allocation being
   126  // unknown.
   127  func NewErrUnknownAllocation(allocID string) error {
   128  	return fmt.Errorf("%s %q", ErrUnknownAllocationPrefix, allocID)
   129  }
   130  
   131  // NewErrUnknownNode returns a new error caused by the node being unknown.
   132  func NewErrUnknownNode(nodeID string) error {
   133  	return fmt.Errorf("%s %q", ErrUnknownNodePrefix, nodeID)
   134  }
   135  
   136  // NewErrUnknownJob returns a new error caused by the job being unknown.
   137  func NewErrUnknownJob(jobID string) error {
   138  	return fmt.Errorf("%s %q", ErrUnknownJobPrefix, jobID)
   139  }
   140  
   141  // NewErrUnknownEvaluation returns a new error caused by the evaluation being
   142  // unknown.
   143  func NewErrUnknownEvaluation(evaluationID string) error {
   144  	return fmt.Errorf("%s %q", ErrUnknownEvaluationPrefix, evaluationID)
   145  }
   146  
   147  // NewErrUnknownDeployment returns a new error caused by the deployment being
   148  // unknown.
   149  func NewErrUnknownDeployment(deploymentID string) error {
   150  	return fmt.Errorf("%s %q", ErrUnknownDeploymentPrefix, deploymentID)
   151  }
   152  
   153  // IsErrUnknownAllocation returns whether the error is due to an unknown
   154  // allocation.
   155  func IsErrUnknownAllocation(err error) bool {
   156  	return err != nil && strings.Contains(err.Error(), ErrUnknownAllocationPrefix)
   157  }
   158  
   159  // IsErrUnknownNode returns whether the error is due to an unknown
   160  // node.
   161  func IsErrUnknownNode(err error) bool {
   162  	return err != nil && strings.Contains(err.Error(), ErrUnknownNodePrefix)
   163  }
   164  
   165  // IsErrUnknownJob returns whether the error is due to an unknown
   166  // job.
   167  func IsErrUnknownJob(err error) bool {
   168  	return err != nil && strings.Contains(err.Error(), ErrUnknownJobPrefix)
   169  }
   170  
   171  // IsErrUnknownEvaluation returns whether the error is due to an unknown
   172  // evaluation.
   173  func IsErrUnknownEvaluation(err error) bool {
   174  	return err != nil && strings.Contains(err.Error(), ErrUnknownEvaluationPrefix)
   175  }
   176  
   177  // IsErrUnknownDeployment returns whether the error is due to an unknown
   178  // deployment.
   179  func IsErrUnknownDeployment(err error) bool {
   180  	return err != nil && strings.Contains(err.Error(), ErrUnknownDeploymentPrefix)
   181  }
   182  
   183  // IsErrUnknownNomadVersion returns whether the error is due to Nomad being
   184  // unable to determine the version of a node.
   185  func IsErrUnknownNomadVersion(err error) bool {
   186  	return err != nil && strings.Contains(err.Error(), errUnknownNomadVersion)
   187  }
   188  
   189  // IsErrNodeLacksRpc returns whether error is due to a Nomad server being
   190  // unable to connect to a client node because the client is too old (pre-v0.8).
   191  func IsErrNodeLacksRpc(err error) bool {
   192  	return err != nil && strings.Contains(err.Error(), errNodeLacksRpc)
   193  }
   194  
   195  func IsErrNoSuchFileOrDirectory(err error) bool {
   196  	return err != nil && strings.Contains(err.Error(), "no such file or directory")
   197  }
   198  
   199  // NewErrRPCCoded wraps an RPC error with a code to be converted to HTTP status
   200  // code
   201  func NewErrRPCCoded(code int, msg string) error {
   202  	return fmt.Errorf("%s%d,%s", errRPCCodedErrorPrefix, code, msg)
   203  }
   204  
   205  // NewErrRPCCodedf wraps an RPC error with a code to be converted to HTTP
   206  // status code.
   207  func NewErrRPCCodedf(code int, format string, args ...interface{}) error {
   208  	msg := fmt.Sprintf(format, args...)
   209  	return fmt.Errorf("%s%d,%s", errRPCCodedErrorPrefix, code, msg)
   210  }
   211  
   212  // CodeFromRPCCodedErr returns the code and message of error if it's an RPC error
   213  // created through NewErrRPCCoded function.  Returns `ok` false if error is not
   214  // an rpc error
   215  func CodeFromRPCCodedErr(err error) (code int, msg string, ok bool) {
   216  	if err == nil || !strings.HasPrefix(err.Error(), errRPCCodedErrorPrefix) {
   217  		return 0, "", false
   218  	}
   219  
   220  	headerLen := len(errRPCCodedErrorPrefix)
   221  	parts := strings.SplitN(err.Error()[headerLen:], ",", 2)
   222  	if len(parts) != 2 {
   223  		return 0, "", false
   224  	}
   225  
   226  	code, err = strconv.Atoi(parts[0])
   227  	if err != nil {
   228  		return 0, "", false
   229  	}
   230  
   231  	return code, parts[1], true
   232  }