module Ganeti.Errors
( ErrorCode(..)
, GanetiException(..)
, ErrorResult
, errToResult
, errorExitCode
, excName
, formatError
, ResultG
, maybeToError
) where
import Text.JSON hiding (Result, Ok)
import System.Exit
import Ganeti.THH
import Ganeti.BasicTypes
import qualified Ganeti.Constants as C
$(declareSADT "ErrorCode"
[ ("ECodeResolver", 'C.errorsEcodeResolver)
, ("ECodeNoRes", 'C.errorsEcodeNores)
, ("ECodeTempNoRes", 'C.errorsEcodeTempNores)
, ("ECodeInval", 'C.errorsEcodeInval)
, ("ECodeState", 'C.errorsEcodeState)
, ("ECodeNoEnt", 'C.errorsEcodeNoent)
, ("ECodeExists", 'C.errorsEcodeExists)
, ("ECodeNotUnique", 'C.errorsEcodeNotunique)
, ("ECodeFault", 'C.errorsEcodeFault)
, ("ECodeEnviron", 'C.errorsEcodeEnviron)
])
$(makeJSONInstance ''ErrorCode)
$(genException "GanetiException"
[ ("GenericError", [excErrMsg])
, ("LockError", [excErrMsg])
, ("PidFileLockError", [excErrMsg])
, ("HypervisorError", [excErrMsg])
, ("ProgrammerError", [excErrMsg])
, ("BlockDeviceError", [excErrMsg])
, ("ConfigurationError", [excErrMsg])
, ("ConfigVerifyError", [excErrMsg, ("allErrors", [t| [String] |])])
, ("ConfigVersionMismatch", [ ("expVer", [t| Int |])
, ("actVer", [t| Int |])])
, ("ReservationError", [excErrMsg])
, ("RemoteError", [excErrMsg])
, ("SignatureError", [excErrMsg])
, ("ParameterError", [excErrMsg])
, ("ResultValidationError", [excErrMsg])
, ("OpPrereqError", [excErrMsg, ("errCode", [t| ErrorCode |])])
, ("OpExecError", [excErrMsg])
, ("OpResultError", [excErrMsg])
, ("OpCodeUnknown", [excErrMsg])
, ("JobLost", [excErrMsg])
, ("JobFileCorrupted", [excErrMsg])
, ("ResolverError", [ ("errHostname", [t| String |])
, ("errResolverCode", [t| Int |])
, ("errResolverMsg", [t| String |])])
, ("HooksFailure", [excErrMsg])
, ("HooksAbort", [("errs", [t| [(String, String, String)] |])])
, ("UnitParseError", [excErrMsg])
, ("ParseError", [excErrMsg])
, ("TypeEnforcementError", [excErrMsg])
, ("X509CertError", [ ("certFileName", [t| String |])
, excErrMsg ])
, ("TagError", [excErrMsg])
, ("CommandError", [excErrMsg])
, ("StorageError", [excErrMsg])
, ("InotifyError", [excErrMsg])
, ("JobQueueError", [excErrMsg])
, ("JobQueueDrainError", [excErrMsg])
, ("JobQueueFull", [])
, ("ConfdMagicError", [excErrMsg])
, ("ConfdClientError", [excErrMsg])
, ("UdpDataSizeError", [excErrMsg])
, ("NoCtypesError", [excErrMsg])
, ("IPAddressError", [excErrMsg])
, ("LuxiError", [excErrMsg])
, ("QueryFilterParseError", [excErrMsg])
, ("RapiTestResult", [excErrMsg])
, ("FileStoragePathError", [excErrMsg])
])
instance JSON GanetiException where
showJSON = saveGanetiException
readJSON = loadGanetiException
instance FromString GanetiException where
mkFromString = GenericError
type ErrorResult = GenericResult GanetiException
$(genStrOfOp ''GanetiException "excName")
errorExitCode :: GanetiException -> ExitCode
errorExitCode (ConfigurationError {}) = ExitFailure 2
errorExitCode (ConfigVerifyError {}) = ExitFailure 2
errorExitCode _ = ExitFailure 1
formatError :: GanetiException -> String
formatError (ConfigurationError msg) =
"Corrupt configuration file: " ++ msg ++ "\nAborting."
formatError (ConfigVerifyError msg es) =
"Corrupt configuration file: " ++ msg ++ "\nAborting. Details:\n"
++ unlines es
formatError (HooksAbort errs) =
unlines $
"Failure: hooks execution failed:":
map (\(node, script, out) ->
" node: " ++ node ++ ", script: " ++ script ++
if null out
then " (no output)"
else ", output: " ++ out
) errs
formatError (HooksFailure msg) =
"Failure: hooks general failure: " ++ msg
formatError (ResolverError host _ _) =
"Failure: can't resolve hostname " ++ host
formatError (OpPrereqError msg code) =
"Failure: prerequisites not met for this" ++
" operation:\nerror type: " ++ show code ++ ", error details:\n" ++ msg
formatError (OpExecError msg) =
"Failure: command execution error:\n" ++ msg
formatError (TagError msg) =
"Failure: invalid tag(s) given:\n" ++ msg
formatError (JobQueueDrainError _)=
"Failure: the job queue is marked for drain and doesn't accept new requests"
formatError JobQueueFull =
"Failure: the job queue is full and doesn't accept new" ++
" job submissions until old jobs are archived"
formatError (TypeEnforcementError msg) =
"Parameter Error: " ++ msg
formatError (ParameterError msg) =
"Failure: unknown/wrong parameter name '" ++ msg ++ "'"
formatError (JobLost msg) =
"Error checking job status: " ++ msg
formatError (QueryFilterParseError msg) =
"Error while parsing query filter: " ++ msg
formatError (GenericError msg) =
"Unhandled Ganeti error: " ++ msg
formatError err =
"Unhandled exception: " ++ show err
type ResultG = ResultT GanetiException IO
errToResult :: ErrorResult a -> Result a
errToResult (Ok a) = Ok a
errToResult (Bad e) = Bad $ formatError e
maybeToError :: String -> Maybe a -> ErrorResult a
maybeToError _ (Just a) = Ok a
maybeToError m Nothing = Bad $ GenericError m