The new predicate contains the only one parameter ``user`` that equals to the authorized RAPI user submitted a job. If the user is unauthorized (RAPI authentication disabled) or a job hasn't been submitted via RAPI, the parameter will contain an empty string.
Signed-off-by: Oleg Ponomarev <[email protected]> --- man/gnt-filter.rst | 6 ++++++ src/Ganeti/JQScheduler/Filtering.hs | 14 ++++++++++++++ src/Ganeti/Objects.hs | 3 +++ 3 files changed, 23 insertions(+) diff --git a/man/gnt-filter.rst b/man/gnt-filter.rst index 1a5bbab..40a59e0 100644 --- a/man/gnt-filter.rst +++ b/man/gnt-filter.rst @@ -58,6 +58,12 @@ Filter rules consist of the following: This predicate is true, if one of the entries of one of the opcodes in this job satisfies the expression. + - ``user``. Only parameter is a boolean expression. + For this expression, there is only one field available ``user``, + which represents the authorized user submitted a job via RAPI. + If a job is submitted by any other interface or an authentication is + turned off in RAPI, it will contain an empty string. + - An ``action``. One of: - ACCEPT. The job will be accepted; no further filter rules diff --git a/src/Ganeti/JQScheduler/Filtering.hs b/src/Ganeti/JQScheduler/Filtering.hs index 8c98083..603b45d 100644 --- a/src/Ganeti/JQScheduler/Filtering.hs +++ b/src/Ganeti/JQScheduler/Filtering.hs @@ -50,6 +50,7 @@ import qualified Data.Set as Set import qualified Text.JSON as J import Ganeti.BasicTypes +import Ganeti.Constants (opcodeReasonSrcRlib2, opcodeReasonAuthUser) import Ganeti.Errors import Ganeti.Lens hiding (chosen) import Ganeti.JQScheduler.Types @@ -87,6 +88,16 @@ reasonsOf job = job ^.. qjOpsL . traverse . qoInputL . validOpCodeL . metaParamsL . opReasonL . traverse +-- | Authenticated RAPI user submitted a job. It's always the last entry +userOf :: QueuedJob -> String -> String +userOf job default_user = + foldl extractRapiUser default_user $ reasonsOf job + where extractRapiUser current_user (source, reason, _) = + if source == opcodeReasonSrcRlib2 + then fromMaybe current_user (stripPrefix opcodeReasonAuthUser reason) + else current_user + + -- | Like `evaluateFilterM`, but allowing only `Comparator` operations; -- all other filter language operations are evaluated as `False`. -- @@ -141,6 +152,9 @@ matchPredicate job watermark predicate = case predicate of "timestamp" -> Just $ NumericValue timestamp `comp` val _ -> Nothing in any reasonMatches (reasonsOf job) + FPUser fil -> evaluateFilterComparator fil $ \comp field val -> case field of + "user" -> Just $ (QuotedString $ userOf job "") `comp` val + _ -> Nothing -- | Whether all predicates of the filter rule are true for the job. diff --git a/src/Ganeti/Objects.hs b/src/Ganeti/Objects.hs index 52a00fb..a81389a 100644 --- a/src/Ganeti/Objects.hs +++ b/src/Ganeti/Objects.hs @@ -525,6 +525,7 @@ data FilterPredicate = FPJobId (Filter FilterField) | FPOpCode (Filter FilterField) | FPReason (Filter FilterField) + | FPUser (Filter FilterField) deriving (Eq, Ord, Show) @@ -533,6 +534,7 @@ instance JSON FilterPredicate where FPJobId expr -> JSArray [string "jobid", showJSON expr] FPOpCode expr -> JSArray [string "opcode", showJSON expr] FPReason expr -> JSArray [string "reason", showJSON expr] + FPUser expr -> JSArray [string "user", showJSON expr] where string = JSString . toJSString @@ -542,6 +544,7 @@ instance JSON FilterPredicate where | name == toJSString "jobid" -> FPJobId <$> readJSON expr | name == toJSString "opcode" -> FPOpCode <$> readJSON expr | name == toJSString "reason" -> FPReason <$> readJSON expr + | name == toJSString "user" -> FPUser <$> readJSON expr JSArray (JSString name:params) -> fail $ "malformed FilterPredicate: bad parameter list for\ \ '" ++ fromJSString name ++ "' predicate: " -- 2.6.0.rc2.230.g3dd15c0
