Search code examples
taskscheduled-tasksmarklogic

query run from task server cannot find documents?


I have a XQuery defined that I can run from the Query Console(QC). I have a task setup on the task server.

The query seems unable to find the documents searched for, so this must be a permissions problem is my guess.

The task query:

xquery version "1.0-ml";

import module namespace object = "http://marklogic.com/solutions/obi/object" at 
  "/ext/obi/lib/object-query-lib.xqy",
  "/ext/obi/lib/object-service-lib.xqy",
  "/ext/obi/lib/object-lib.xqy";

declare namespace obj="http://marklogic.com/solutions/obi/object";

declare namespace alt="http://example.com/sccs/alert";
declare namespace scc="http://example.com/sccs";
declare namespace source="http://marklogic.com/solutions/obi/source";

(: Start task :)
let $_ := xdmp:log("******* START CHECK UPDATE ALERTS TASK *********")
(: Find al active alerts :)
let $alerts := cts:search(
                        collection("object"),                
                        cts:and-query((
                                        cts:element-range-query(xs:QName("obj:type"), "=", "alert"),
                                        cts:element-range-query(xs:QName("alt:status"), "=", "Active")
                                        (:
                                        cts:element-range-query(xs:QName("alt:device-id"), "=", $device-id)
                                        :)
                                        ))
                        )/obj:object

let $update-object-content :=  <alert xmlns="http://example.com/sccs/alert">
                                    <obj:property>
                                        <status xmlns="http://example.com/sccs/alert">Inactive</status>
                                    </obj:property>
                                </alert>

let $now := fn:current-dateTime()
(: minimum duration before alerts turns inactive :)
let $duration-min := xs:dayTimeDuration('PT25M0S') (: defines 30 minutes :)

(: loop over all active alerts :)
let $_ := 
    for $a in $alerts
        let $a-id := $a//obj:id/text()
        let $s-id := $a//source:id/text()[1]
        let $timestamp := xdmp:parse-dateTime('[Y0001]-[M01]-[D01]T[h01]:[m01]:[s01]',$a//scc:timestamp/text())
        (: if Alert is older then $delta then set status to Inactive :)
        let $delta := $now - $timestamp
        let $upd := if ($delta > $duration-min) then
                      ( 
                      let $_ := xdmp:log(fn:concat("Update Alert ID : ",$a-id," to INACTIVE."))
                      let $detail-id := obj:add-details($a-id, $update-object-content, $s-id,())
                      return $detail-id
                      )
                    else ()
    return $upd

let $_ := xdmp:log(fn:concat("DEBUG NUM ALERTS:",fn:count($alerts)))

return ()

Task defenition :

      <scheduled-task>
        <task-path>/tasks/update-alerts-to-inactive.xqy</task-path>
        <task-root>/</task-root>
        <task-type>minutely</task-type>
        <task-period>5</task-period>
        <task-database name="${content-db}"/>
        <task-modules name="${app-modules-db}"/>
        <task-user name="${app-name}-user"/>
      </scheduled-task>

The task checks every 5 minutes if alert objects need to be set to "Inactive".

From the log Error.txt I can see the tasks runs but cannot find the docs.

2015-10-26 00:45:00.395 Info: TaskServer: ******* START CHECK UPDATE ALERTS TASK *********
2015-10-26 00:45:00.395 Info: TaskServer: DEBUG NUM ALERTS:0

I run all code in codepoint root collation but cannot find anything wrt the taskserver in this context.

The documentation on permissions needed for the user to perform a task are very cryptical:

In the Task User and Task Host fields, specify the user with permission to invoke the task and the host computer on which the task is to be invoked. If no host is specified, then the task runs on all hosts. The user specified in the Task User field must have the privileges required to execute the functions used in the module. See Appendix B: Pre-defined Execute Privileges for the full list of execute privileges.

Question: Why cant the app-user find the documents when on the task server?

UPDATE

Tried to get permissions on the OBI document but fail.

This is the code (as suggested by Dave)

import module namespace sec="http://marklogic.com/xdmp/security" at 
  "/MarkLogic/security.xqy";

declare namespace obj="http://marklogic.com/solutions/obi/object";

let $o-id := cts:search(
                        collection("object"),                
                        cts:and-query((
                                        cts:element-range-query(xs:QName("obj:type"), "=", "alert")
                                        ))
                       )/obj:object/obj:id/text()

let $uri := object:master-uri($o-id)

let $res := for $perm in xdmp:document-get-permissions($uri)
    let $role-name := sec:get-role-names($perm/sec:role-id)
    return $role-name || ": " || $perm/sec:capability/fn:string()

let $string-uri := '/marklogic.solutions.obi/object/cec48c59-a648-4da5-a758-2b6bb4065279.xml'

return xdmp:document-get-permissions($string-uri)

I am running this as admin on the QC, it returns empty sequence...


Solution

  • The simplest way to check the permissions part of this is to run your code in Query Console as ${app-name}-user}. Either connect to Query Console as that user, or wrap the code in an xdmp:eval() and specify the user in the options. I'd expect you'd get the same result.

    This does not appear to be a problem with execute permissions, since it appears that the task did run.

    In Query Console, run this code:

    import module namespace sec="http://marklogic.com/xdmp/security" at 
      "/MarkLogic/security.xqy";
    
    for $perm in xdmp:document-get-permissions($uri)
    let $role-name := sec:get-role-names($perm/sec:role-id)
    return $role-name || ": " || $perm/sec:capability/fn:string()
    

    ... substituting the URI of one of your target documents for $uri. That will tell you what roles have what permissions on that document. Now you can check whether ${app-name}-user has (or inherits) that role.