GithubHelp home page GithubHelp logo

irods_rule_engine_plugin_python's Introduction

iRODS Rule Engine Plugin - Python

This C++ plugin provides the iRODS platform a rule engine that allows iRODS rules to be written in Python.

Build

Building the iRODS Python Rule Engine Plugin requires version 4.2.1+ of the iRODS software from github (http://github.com/irods/irods). The version of the irods-dev package will need to match the version defined in CMakeLists.txt.

cd irods_rule_engine_plugin_python
mkdir build
cd build
cmake ../
make package

Installation

The packages produced by CMake will install the Python plugin shared object file:

/usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so

Configuration

After installing the plugin, /etc/irods/server_config.json needs to be configured to use the plugin.

To activate the plugin, add a new stanza to the "rule_engines" array within server_config.json:

{
    "instance_name": "irods_rule_engine_plugin-python-instance",
    "plugin_name": "irods_rule_engine_plugin-python",
    "plugin_specific_configuration": {}
}

Adding the Python Rule Engine Plugin stanza above the default "irods_rule_engine_plugin-irods_rule_language" stanza will allow any defined Python rules to take precedence over any similarly named rules in the iRODS Rule Language. Placing the "irods_rule_engine_plugin-python-instance" stanza before the "irods_rule_engine_plugin-cpp_default_policy-instance" stanza will ensure that any default C++ policies will not cancel out any similarly named Python rules.

As soon as the stanza is inserted, the iRODS server expects a Python source code module to exist at the path /etc/irods/core.py. Once imported by the iRODS server and successfully compiled to a Python byte-code file bearing the ".pyc" extension, any functions in the module will be callable as rules as long as they conform to a calling convention

def a_python_rule( rule_args, callback, rei ):
    # ... Python code to be executed in the rule context...

The parameters need not be explicit or even named as they are here; they could in fact be collapsed into a parameter tuple, as in pyfn(*x).

The first argument above, rule_args, is a tuple containing the optional, positional parameters fed to the rule function by its caller; these same parameters may be written to, with the effect that the written values will be returned to the caller. The callback object is effectively a gateway through which other rules (even those managed by other rule engine plugins) and microservices may be called. Finally, rei (also known as "rule execution instance") is an object carrying iRODS-related context for the current rule call, including any session variables.

When the plugin is freshly installed, a template file is located at /etc/irods/core.py.template. This may be copied to /etc/irods/core.py, or else an empty core.py can be created at that path if the user prefers to begin from scratch.

Default PEPs

The example core.py.template file in this repository contains a Python implementation of all static policy enforcement points (PEPs), equivalent to the default core.re rulebase. Placing the "irods_rule_engine_plugin-python-instance" stanza before the "irods_rule_engine_plugin-cpp_default_policy-instance" stanza in /etc/irods/server_config.json will ensure that any default C++ policies will not cancel out any similarly named Python rules copied from the example core.py.template file.

Python Version

This version of the Python Rule Engine Plugin uses the Python 2.7 interpreter.

Remote Execution

There exists a requirement for the implementation of a different remote microservice call for every rule language. Given the possibility of a namespace collision with more than one rule language being configured simultaneously, the name of the microservice to use for the python language is py_remote(). As with remote execution via the native rule engine, this microservice runs the given rule text on the remote host using exec_rule_text. This can be done on any iRODS host (inside or outside the local zone) where the invoking user is authenticated.

The microservice's signature is: py_remote(hostname, hints, code, recovery).

Its four parameters are strings:

  • hostname. The name of the iRODS server where the code is to be executed.
  • hints. A string containing optional XML tags. Currently scanned only for the INST_NAME tag, and other tags - if used - will be ignored. This includes , since the zone (whether remote or local) is inferred from the hostname parameter.
  • code. The Python source code to be executed, in the form of a complete rule, i.e.: def main(rule_args,callback,rei): ...
  • recovery. This is currently unused.

For example:

def main(rule_args, callback, rei):
    rule_code = "def main(rule_args, callback, rei):\n    print('This is a test of the Python Remote Rule Execution')"
    callback.py_remote('icat.example.org', '<INST_NAME>irods_rule_engine_plugin-python-instance</INST_NAME>', rule_code, '')
INPUT null
OUTPUT ruleExecOut

Admin rights required for irule with Python

Due to the Python language not being sandboxed (and running as the unix iRODS service account), irule does not allow rulefiles written in Python to be executed by non-rodsadmin user accounts. If this is attempted, the following error message will be returned to the client:

Insufficient privileges to run irule in Python rule engine plugin

If Python rules are needed by non-rodsadmin users, then iRODS administrators can install those Python rules on the server side (in core.py, or imported by core.py) where they will be made available to irule via the callback mechanism (see below).

Calling rules across language boundaries

The following example rulefiles (iRODS Rule Language and Python) demonstrate calling microservices in both directions when reacting to a simple iput (the acPostProcForPut PEP is fired in Python).

The Python acPostProcForPut rule calls irods_rule_language_printme with a single string parameter via the callback mechanism.

The iRODS Rule Language rule calls python_printme with a single string parameter (without using the callback mechanism).

core.py:

def acPostProcForPut(rule_args, callback, rei):
    callback.writeLine('serverLog', 'PYTHON - acPostProcForPut() begin')
    callback.irods_rule_language_printme('apples')
    callback.writeLine('serverLog', 'PYTHON - acPostProcForPut() end')

def python_printme(rule_args, callback, rei):
    callback.writeLine('serverLog', 'PYTHON - python_printme() begin')
    callback.writeLine('serverLog', 'python_printme [' + rule_args[0] + ']')
    callback.writeLine('serverLog', 'PYTHON - python_printme() end')

example.re:

irods_rule_language_printme(*thestring){
    writeLine("serverLog","irods_rule_language_printme [" ++ *thestring ++ "]")
    python_printme('bananas');
}

Put a file:

$ iput foo

The resulting rodsLog will have the following output:

Aug  8 20:57:43 pid:23802 NOTICE: writeLine: inString = PYTHON - acPostProcForPut() begin
Aug  8 20:57:43 pid:23802 NOTICE: writeLine: inString = irods_rule_language_printme [apples]
Aug  8 20:57:43 pid:23802 NOTICE: writeLine: inString = PYTHON - python_printme() begin
Aug  8 20:57:43 pid:23802 NOTICE: writeLine: inString = python_printme [bananas]
Aug  8 20:57:43 pid:23802 NOTICE: writeLine: inString = PYTHON - python_printme() end
Aug  8 20:57:43 pid:23802 NOTICE: writeLine: inString = PYTHON - acPostProcForPut() end

Python globals and built-in modules

These built-in objects are set up at plugin initialization time and available in the python interpreter that loads core.py or, as the case may be, the Python rule file:

  • irods_rule_vars - a dictionary for accessing variables of the form *var from the INPUT line, if present.
  • irods_types - a module containing common struct types used for communicating with microservices.
  • irods_errors - a module mapping well-known iRODS error names to their corresponding integer values.
  • global_vars - deprecated alias for irods_rule_vars; only available in some contexts. Will be removed in a future release.

By using the irods_errors built-in, policy may indicate how the framework is to continue through the use of a symbolic name, rather than a cryptic number reference:

def pep_api_data_obj_put_pre(args, callback, rei):
  # ...local processing...
  return irods_errors.RULE_ENGINE_CONTINUE  # compare: "return 5000000"

Finally, the following example demonstrates the use of all three of these built-ins. With the below rule contained anywhere in the Python rulebase:

def testRule(rule_args, callback, rei):
  from irods_errors import USER_FILE_DOES_NOT_EXIST
  check_err = lambda e,errcode: e.message.startswith('[iRods__Error__Code:{}]'.format(errcode))
  try:
    ret_val = callback.msiObjStat(rule_args[0], irods_types.RodsObjStat())
  except RuntimeError, e:
    if check_err(e, USER_FILE_DOES_NOT_EXIST):
      callback.writeLine('serverLog', 'ERROR in testRule: "'+rule_args[0]+'" not found')
    else:
      callback.writeLine('serverLog', 'UNKNOWN error')
    rule_args[0] = ''
  else:
    objstat_return = ret_val['arguments'][1]
    rule_args[0] = 'mtime = {!s} ; objsize = {!s} '.format(objstat_return.modifyTime, objstat_return.objSize)

and a rule script file (named call_testRule.r) which calls testRule with a data path argument:

def main(_,callback,rei):
  data_path = irods_rule_vars[ '*dataPath' ][1:-1]
  retval = callback.testRule( data_path )
  callback.writeLine( "stdout", retval['arguments'][0])
INPUT *dataPath=""
OUTPUT ruleExecOut

we can invoke the rule script and point *dataPath at a trial data object path:

irule -r irods_rule_engine_plugin-python-instance -F call_testRule.r '*dataPath="/full/path/to/data/object"'

and thus determine a data object's existence, as well as its mtime and size, if it does exist.

Auxiliary Python Modules

Included with the PREP (Python Rule Engine Plugin) are some other modules that provide a solid foundation of utility for writers of Python rule code. The plugin directly loads only the module /etc/irods/core.py, however any import statements in that file are honored if the modules they target are in the interpreter's import path (sys.path). In addition, a rodsadmin irods user may use irule to execute Python rules within .r files. By default, /etc/irods is included in the import path, meaning that the modules discussed in this section are accessible to all other Python modules and functions (whether or not they are "rules" proper) whether they be internal to core.py, or otherwise loaded by the PREP.

session_vars.py

This module contains a function get_map which may be used to extract session variables from the rei parameter passed to any rule function.

An example follows:

import session_vars
def get_irods_username (rule_args, callback, rei):
  username = ''
  var_map = session_vars.get_map(rei)
  user_type = rule_args[0] or 'client_user'
  userrec = var_map.get(user_type,'')
  if userrec:
    username = userrec.get('user_name','')
  rule_args [0] = username

Special methods

Some iRODS objects used with rules and microservices have been given utility methods.

An example is the map() method of a PluginContext PEP argument:

    def pep_resource_resolve_hierarchy_pre(rule_args, callback, rei):
        import pprint
        pprint.pprint(rule_args[1].map().items())

In version 4.2.11.2 of the Python plugin, BytesBuf has methods to set and access byte content. These can be used to achieve true binary reads and writes, to and from data objects.

For example:

    def my_rule(args, callback, rei):
        buf = irods_types.BytesBuf()
        buf.set_buffer( os.urandom(256) )
        callback.msiDataObjectWrite( descriptor, buf, 0)  #-- Write the buffer.
        # ...
        buf.clear_buffer()

or:

    # ...
    retv = callback.msiDataObjectRead( descriptor, "256", irods_types.BytesBuf())
    returnbuf = retv['arguments'][2]
    out = returnbuf.get_bytes()         #--  Returns list of integer octets.
    start_byte = returnbuf.get_byte(0)  #--  Returns first octet

genquery.py

This module offers writers of Python rules a convenient facility for querying and iterating over objects in the iRODS object catalog (ICAT). The only declaration required within your core.py or other Python rule file is:

from genquery import *

Previous versions of the genquery.py module offered the following two styles of iterator to expose iRODS' General Query capability:

  • row_iterator, a generator function which yields results one row at a time:
def my_rule(rule_args,callback,rei):
    for result in row_iterator("COLL_NAME,DATA_NAME",
                               "DATA_NAME like '%.dat'",
                               AS_LIST,
                               callback):
        callback.writeLine( "serverLog", result[0] + "/" + result[1] )
  • paged_iterator, an iterator class that enables paging through a total of nResults rows from the ICAT in lists of 1 <= n <= N at a time, with
    • N a specified page size in the range 1...256 inclusive;
    • and n < N only at the end of the iteration when nResults == 0 or nResults % N != 0:
def get_users_in_group(args,callback,rei):
    groupname = args[0]
    users = []
    for rows in paged_iterator("USER_NAME,USER_ZONE",
                                  "USER_GROUP_NAME = '{}'".format(groupname),
                                  AS_DICT, callback, 32 ):
        users += ["{USER_NAME}#{USER_ZONE}".format(**r) for r in rows]
    callback.writeLine('stdout',repr(users))

As of version 4.2.8 of iRODS, there is also a class-based iterator called Query, which offers an enhanced set of options and behaviors for use in ICAT searches.

Under the new class-based syntax, an iRODS general query can be as simple as in this example:

all_resource_names = [ r for r in Query(callback,'RESC_NAME') ]

the result of which will be a Python list of str values, enumerating the names of all resource nodes known to the ICAT.

Query's constructor allows commonly defaulted attributes (otherwise tunable via a selection of keyword arguments, listed in the reference at the end of this section) to take on reasonable values. In particular, the output attribute (dictating the type of data structure used to return individual row results) will, unless specified, default to AS_TUPLE -- meaning that for single-column query results the iterator variable does not need to be indexed. That is why, in our first Query example, the values yielded by the iteration were strings.

This allows for an admirable consistency of expression, as can be seen in the following two examples:

    for id in Query(callback, "DATA_ID") :
        pass # - process data id's for iterated objects

and

    for coll,data in Query(callback,("COLL_NAME", "DATA_NAME")):
        pass # - process result data objects using the logical path: (coll + "/" + data)

A caveat for beginners however, when expanding on such deceptively simple syntax, is that the iterations in the above two example usages yield essentially different row types. In the first usage, the iteration variable id is of type str (string); and in the second, a tuple is actually returned from each iteration and then automatically unpacked as the variables coll and data.

If the uniformity of the result rows' data structure type is desirable for a given application of Query(...), then output=AS_LIST or output=AS_DICT should be favored to the default output=AS_TUPLE. For more on this and other query attributes, see the reference at the end of this section.

Clones and Copies

The Query class features lazy execution, meaning that only the act of iterating on a Query object will actually connect to the ICAT for the purpose of a general query. This has some advantages, particularly those of cheap instantiation and duplication.

Specifically, the copy method can be invoked on any Query object to instantiate a new one, and this can be done either with or without keyword arguments. Absent any input arguments, a call to the copy method simply clones the original object.

The keyword arguments to Query's copy method, if used, are identical to those used by the constructor, and allow modification of the corresponding attributes within the new object. In this way, a Query object can easily serve as a bag of attribute variables which can be stored, transferred, modified, and re-used.

Because iteration on a Query object can change its state, a best practice is to favor invoking the copy method wherever repeated (esp. overlapping) uses are possible for the same Query instance. This is particularly true for a Query object that has been stored in a Python object or variable, so as to give it a longer lifetime than a temporary instance.

To demonstrate how this could look in practice, let's incorporate a more elaborate version of the search from our first Query example within the following helper function:

def get_resource_details(callback,*args):
    (cond_string,) = args[:1] if args else ('',)
    my_query = Query( callback,
                      columns = ['RESC_NAME'],
                      conditions = cond_string )
    n_nodes = my_query.copy().total_rows()
    if n_nodes == 0: return []

    details = my_query.copy( columns = \
                               my_query.columns + ['RESC_ID','RESC_PARENT'] )
    return [
      "Resource '{}': id = {}, parent-id = {}".format(row[0],row[1],row[2])
      for row in details
    ]

which could later be called thus:

def my_resc_summaries(_,callback,rei):
    import socket; hostname = socket.gethostname()
    from pprint import pformat
    # -- all resources listed in the ICAT --
    callback.writeLine('stdout',pformat(    get_resource_details(callback)
                                )+"\n---\n")
    # -- all resources on the local machine --
    callback.writeLine('stdout',pformat(    get_resource_details(callback,
                                            "RESC_LOC = '{}'".format(hostname))
                                )+"\n---\n")
    # -- all resources having no parent node -- (ie root resources)
    callback.writeLine('stdout', pformat(   get_resource_details(callback,
                                                                 "RESC_PARENT = ''")))
    #...

Auto joins

In iRODS's general queries, joins between related tables are automatic. For example, queries whose column targets including both DATA_* and COLL_* fields implicitly perform "auto-joins" between the Data objects queried and their parent Collections. Metadata AVU's are also joined automatically with the corresponding type of iRODS object which they annotate:

q = Query( callback, columns = ['DATA_ID,META_DATA_ATTR_VALUE'], output = AS_DICT, conditions = """\
            META_DATA_ATTR_NAME = 'modify_time' and \
            META_DATA_ATTR_VALUE like '0%'
    """)
number_of_data_objects = q.total_rows() # counting only, no fetch operations
q_fetch = q.copy( q.columns + ["COLL_NAME", "order(DATA_SIZE)"] )
for row in q_fetch:
    log_record = """id = {DATA_ID} ; size = {order(DATA_SIZE)} ; path = \
                    {COLL_NAME}/{DATA_NAME}; mtime = {META_DATA_ATTR_VALUE}\
                 """.format(**row)
    callback.writeLine("serverLog",log_record)

Query Options

The options Query attribute is a mask of bit-field values which can be built up from constants in the genquery.Options namespace, although probably the only directly useful option is NO_DISTINCT. This option might come into play in the rare case that we decide against iRODS' usual behavior of requiring all row results to be "distinct" (in other words, distinguishable combinations of values for the columns selected):

from genquery import * ; from genquery import Option
y = len([ row for row in Query(callback , 'META_DATA_ATTR_NAME',
                               """META_DATA_ATTR_NAME = 'aa' and \
                                  META_DATA_ATTR_UNITS = '' """,
                               options=Option.NO_DISTINCT) ])

The above example enumerates metadata AVU's (both used and unused) having the attribute name of 'aa' and no units -- and, by employing the NO_DISTINCT option, suppresses the normal de-duplicating behavior of the general query. Without the option, any subset of row results undiscernable as being different would be collapsed into a single row result. (Another example where this might be important would be if multiple data objects had the same values in the DATA_NAME and/or DATA_SIZE columns, without a COLL_* or DATA_ID column also being selected to establish uniqueness in an alternative way.)

Strict upward compatibility mode

As of iRODS 4.2.8, the genquery module's row_iterator function returns a Query instance instead of the generator object of previous versions. This should not affect existing Python rule code that depends on the function unless its return value is expected to follow the generator interface -- allowing, for example, iteration via Python interpreter's next() built-in. The great majority of Python statements and expressions availing themselves of this simple row-iterating facility will use the more convenient and succinct form:

  for row in row_iterator(...)

But in the event of an incompatibility, users can modify their import declarations as follows to accommodate both new and old interfaces simultaneously:

  • Use

    from genquery import *
    from genquery import (row_generator as row_iterator)
    

    in place of the normal

    from genquery import *
    
  • or, in modules not using the wildcard import syntax, add

    from genquery import row_generator
    

    and then replace any problematic uses of row_iterator or genquery.row_iterator with row_generator.

This should solve the very rare issue of such dependencies.

Query object creation and attributes Reference

A Query object's attributes (ie "columns", "conditions", ... ) set constraints on how an iRODS general query should be carried out and how the results should be enumerated. These attributes are defined by keyword arguments of the same name, detailed below.

The Query object constructor requires these two arguments to be first, and in the order listed:

  • callback (not really an attribute) can only be used in the constructor. It is just the callback argument from the enclosing Python rule function's input argument list.
  • columns is a either a string with comma-separated column names, or a list or tuple of column name. If provided among the copy method's keyword arguments, it must however be of type list.

The following arguments are strictly optional and may be used either in Query's constructor or in the copy method:

  • condition is the "where ..." predicate traditionally used in the general query syntax, but omitting the where keyword. The default (an empty string) allows for opting out of the search condition, in which case all objects of the requested type, or joined list of types, will be returned (ie. Collections for COLL_*, Resources for RESC_*)
  • output is one of: AS_TUPLE, AS_DICT or AS_LIST. These constants are defined in the genquery module, and they specify the Python data structure type to be used for returning individual row results.
    • AS_TUPLE, the default, lets results of a single-column query be rendered simply as one string value per row returned; or, if multiple column names are specified, as a tuple of strings, indexed by a zero-based integer column offset. (Note that if a more programmatically consistent interface is desired, ie. indexing each row result by integer offset even for the case of a single column, then AS_LIST should be preferred.)
    • AS_LIST forces a column value within each row to be indexed by its zero-based integer position among the corresponding entry in the columns attribute .
    • AS_DICT lets column values be indexed directly using the column name itself (a string). The seemingly higher convenience of this approach is, however, paid for by an increased per-row execution overhead.
  • offset: 0 by default, this Query attribute dictates the integer position, relative to the complete set of possible rows returned, where the enumeration of query results will start.
  • limit: None by default (ie "no limit"), this option can be an integer >= 1 if specified, and limits the returned row enumeration to the requested number of results. Often used with offset, as defined above.
  • case-sensitive is normally True. If it is set to False, the condition string will be uppercased, and the query will be executed without regard to case. This allows for more permissive matching on the names of resources, collections, data objects, etc.
  • options is a bitmask of extra options, and defaults to a value of 0. genquery.Option.NO_DISTINCT is one such extra option, as is RETURN_TOTAL_ROW_COUNT (although in the latter case, using the Query object's row_count method should be preferred.)

Questions and Answers

What happened to my print output?

In iRODS server versions 4.3.0 and later, all standard streams are redirected to /dev/null in the server. This means that any data sent to stdout such as via a print statement in a rule run inside the server will be discarded.

Here is some example code which would print a message to the rodsLog in servers from the 4.2.x series and earlier when run with the Python Rule Engine Plugin:

print('hello, server log!')

In order to achieve a similar effect on server versions 4.3.0 and later, you can replace such a call like this:

callback.writeLine('serverLog', 'hello, server log!')

Note that the writeLine microservice can also target stdout in addition to serverLog. callback.writeLine('stdout', ...) will have the same effect as running print. The output will be discarded.

irods_rule_engine_plugin_python's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

irods_rule_engine_plugin_python's Issues

callback object exists for delayExec() but not remoteExec()

On a machine with hostname daniel-ThinkPad-W540 , we are observing two scenarios in the use of the python rule engine plugin during calls to delayExec() and remoteExec() . Scenario (1) acts as expected, whereas scenario (2) displays the problem behavior.
Note incidentally that in each scenario, the remote and local computers are the self-same machine, with the implication that rule engine resolution order should be the same remotely as it is locally.

scenario (1):

With the irods rule language plugin preceding the python rule language in the server config's resolution order, and a rule file py_re_testexec.r containing:

def danRule(rule_args, callback, rei):
  callback.delayExec ("<PLUSET>1s</PLUSET>", "writeLine('serverLog','delaytest')","")
  callback.remoteExec ("daniel-ThinkPad-W540","","writeLine('serverLog','remotetest')","")

INPUT null
OUTPUT ruleExecOut

and executed via irule -r irods_rule_engine_plugin-python-instance -F py_re_testexec.r , we arrive at this (expected) output in the serverLog:

May  4 15:50:45 pid:495 NOTICE: writeLine: inString = remotetest
May  4 15:51:13 pid:502 NOTICE: writeLine: inString = delaytest

scenario (2):

Reversing the order of resolution then -- so that the python rule engine plugin comes first and irods rule language second -- and this time using a rule file py_py_testexec.r containing the following (note the callback object is referred to in the rule code because the python rule plugin will be answering):

def danRule(rule_args, callback, rei):
 callback.delayExec ("<PLUSET>1s</PLUSET>", "callback.writeLine('serverLog','delaytest')","")
 callback.remoteExec ("daniel-ThinkPad-W540","","callback.writeLine('serverLog','remotetest')","")

INPUT null
OUTPUT ruleExecOut

After this time invoking via irule -r irods_rule_engine_plugin-python-instance -F py_py_testexec.r we see the following in the server log (after waiting for the output from the delayExec to appear):

May  4 15:52:46 pid:584 remote addresses: 127.0.0.1, 152.54.9.29 ERROR: [exec_rule_text:532] Improperly formatted rule text in Python rule engine plugin
May  4 15:52:46 pid:584 remote addresses: 127.0.0.1, 152.54.9.29 ERROR: rsExecMyRule : -1828000, [-]	/tmp/tmpC8lQD0/irods_rule_engine_plugin-python.cxx:533:irods::error exec_rule_text(const irods::default_re_ctx &, const std::string &, msParamArray_t *, const std::string &, irods::callback) :  status [RULE_ENGINE_ERROR]  errno [] -- message [Improperly formatted rule_text]

May  4 15:52:46 pid:584 DEBUG: 
May  4 15:52:46 pid:584 remote addresses: 127.0.0.1, 152.54.9.29 ERROR: caught python exception: Traceback (most recent call last):
  File "<string>", line 12, in danRule
RuntimeError: [iRods__Error__Code:-1828000] [-]	/tmp/tmpLGq9_F/server/re/include/irods_re_plugin.hpp:321:irods::error irods::dynamic_operation_execution_manager<std::__1::tuple<>, RuleExecInfo *, irods::rule_execution_manager_pack::DONT_AUDIT_RULE>::call(std::string, std::string, OP, As &&...) [T = std::__1::tuple<>, C = RuleExecInfo *, Audit = irods::rule_execution_manager_pack::DONT_AUDIT_RULE, OP = std::__1::function<irods::error (const std::__1::basic_string<char> &, irods::re_pack_inp<std::__1::tuple<> > &, irods::unpack &&)>, As = <const std::__1::basic_string<char> &, irods::re_pack_inp<std::__1::tuple<> > &, irods::unpack>] :  status [RULE_ENGINE_ERROR]  errno [] -- message [applyRuleUpdateParams failed for rule remoteExec]
	[-]	/tmp/tmpLGq9_F/plugins/rule_engines/irods_rule_engine_plugin-irods_rule_language/libirods_rule_engine_plugin-irods_rule_language.cpp:348:irods::error exec_rule(irods::default_re_ctx &, const std::string &, std::list<boost::any> &, irods::callback) :  status [RULE_ENGINE_ERROR]  errno [] -- message [applyRuleUpdateParams failed for rule remoteExec]


May  4 15:52:46 pid:584 remote addresses: 127.0.0.1, 152.54.9.29 ERROR: rsExecMyRule : -1828000, [-]	/tmp/tmpC8lQD0/irods_rule_engine_plugin-python.cxx:539:irods::error exec_rule_text(const irods::default_re_ctx &, const std::string &, msParamArray_t *, const std::string &, irods::callback) :  status [RULE_ENGINE_ERROR]  errno [] -- message [irods_rule_engine_plugin_python::irods::error exec_rule_text(const irods::default_re_ctx &, const std::string &, msParamArray_t *, const std::string &, irods::callback) Caught Python exception.
Traceback (most recent call last):
  File "<string>", line 12, in danRule
RuntimeError: [iRods__Error__Code:-1828000] [-]	/tmp/tmpLGq9_F/server/re/include/irods_re_plugin.hpp:321:irods::error irods::dynamic_operation_execution_manager<std::__1::tuple<>, RuleExecInfo *, irods::rule_execution_manager_pack::DONT_AUDIT_RULE>::call(std::string, std::string, OP, As &&...) [T = std::__1::tuple<>, C = RuleExecInfo *, Audit = irods::rule_execution_manager_pack::DONT_AUDIT_RULE, OP = std::__1::function<irods::error (const std::__1::basic_string<char> &, irods::re_pack_inp<std::__1::tuple<> > &, irods::unpack &&)>, As = <const std::__1::basic_string<char> &, irods::re_pack_inp<std::__1::tuple<> > &, irods::unpack>] :  status [RULE_ENGINE_ERROR]  errno [] -- message [applyRuleUpdateParams failed for rule remoteExec]
	[-]	/tmp/tmpLGq9_F/plugins/rule_engines/irods_rule_engine_plugin-irods_rule_language/libirods_rule_engine_plugin-irods_rule_language.cpp:348:irods::error exec_rule(irods::default_re_ctx &, const std::string &, std::list<boost::any> &, irods::callback) :  status [RULE_ENGINE_ERROR]  errno [] -- message [applyRuleUpdateParams failed for rule remoteExec]


]

May  4 15:53:14 pid:590 NOTICE: writeLine: inString = delaytest

This shows that although the python rule engine is "picking up the phone" for scenario (2) -- as one would predict -- the existence of the callback object, while recognized during the evaluation of the delayExec() call, is NOT recognized during the remoteExec() call.

a BytesBuf has a "void*buf" and "int len", but no means to set content

  • 4-2-stable
  • main

The iRODS primitive data type bytesBuf_t, may be instantiated in the Python RE plugin as irods_types.BytesBuf( ), but it is impractical as an input buffer parameter for the microservice msiDataObjWrite (which accepts it based on its type) because its content and length may not be set. (Strings and bytestrings are also impractical for the purpose, as the write is curtailed at the first NUL character in the string's content, regardless of the length parameter specified to msiDataObjWrite).

I propose adding a method, setbuf(const char*c, int len) , whereby this can be done.

It remains to be seen how boost-python deals with the destruction of such objects when they go away. Possibly all that would be needed is to add a "__del__ method".

plugin generates macro-redefined warnings during compile when pyconfig.h includes feature test macros

  • master
  • 4-2-stable

Both pyconfig.h and feature.h can include definitions for _POSIX_C_SOURCE and _XOPEN_SOURCE. While feature.h contains logic for handling cases in which these defines already exist, pyconfig.h does not.
At present, both of these headers are in the include hierarchy, with feature.h coming in after pyconfig.h, causing the following warnings to be generated:

In file included from /irods_rule_engine_plugin_python/irods_types.cpp:12:
In file included from /irods_rule_engine_plugin_python/init_struct.hpp:5:
In file included from /irods_rule_engine_plugin_python/raw_constructor.hpp:9:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python.hpp:11:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/args.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:50:
/usr/include/python2.7/pyconfig.h:1223:9: warning: '_POSIX_C_SOURCE' macro redefined [-Wmacro-redefined]
#define _POSIX_C_SOURCE 200112L
        ^
/usr/include/features.h:281:10: note: previous definition is here
# define _POSIX_C_SOURCE        200809L
         ^
In file included from /irods_rule_engine_plugin_python/irods_types.cpp:12:
In file included from /irods_rule_engine_plugin_python/init_struct.hpp:5:
In file included from /irods_rule_engine_plugin_python/raw_constructor.hpp:9:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python.hpp:11:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/args.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:50:
/usr/include/python2.7/pyconfig.h:1245:9: warning: '_XOPEN_SOURCE' macro redefined [-Wmacro-redefined]
#define _XOPEN_SOURCE 600
        ^
/usr/include/features.h:207:10: note: previous definition is here
# define _XOPEN_SOURCE  700
         ^
In file included from /irods_rule_engine_plugin_python/irods_rule_engine_plugin-python.cxx:24:
In file included from /irods_rule_engine_plugin_python/irods_rule_engine_plugin-python.hpp:16:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python.hpp:11:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/args.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:50:
/usr/include/python2.7/pyconfig.h:1223:9: warning: '_POSIX_C_SOURCE' macro redefined [-Wmacro-redefined]
#define _POSIX_C_SOURCE 200112L
        ^
/usr/include/features.h:281:10: note: previous definition is here
# define _POSIX_C_SOURCE        200809L
         ^
In file included from /irods_rule_engine_plugin_python/irods_rule_engine_plugin-python.cxx:24:
In file included from /irods_rule_engine_plugin_python/irods_rule_engine_plugin-python.hpp:16:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python.hpp:11:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/args.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:50:
/usr/include/python2.7/pyconfig.h:1245:9: warning: '_XOPEN_SOURCE' macro redefined [-Wmacro-redefined]
#define _XOPEN_SOURCE 600
        ^
/usr/include/features.h:207:10: note: previous definition is here
# define _XOPEN_SOURCE  700

(note: the location of pyconfig.h and the values defined for the macros can vary)

I'll have a pull request for this shortly.

genquery.py double-executes & fetches completed queries

Current genquery.py row_iterator always performs a single extra msiGetMoreRows after all rows are consumed (continue index is already <= 0) (https://github.com/irods/irods_rule_engine_plugin_python/blob/master/genquery.py#L81). This appears to cause the query to be re-executed.

The auto-closing code (https://github.com/irods/irods_rule_engine_plugin_python/blob/master/genquery.py#L101) then has to fetch all query results again, since we are always left with an open query.

The issue does not occur when a query is aborted (i.e. a break or exception occurs before all rows have been yielded), since the query is never re-opened then.

Based on testing against genquery.py of #34 (because I was very curious why there was a performance difference), I see a 1.94x performance difference for a query with 9308 result rows, when all rows are consumed (test rule, data).

pluginContext object not fully populated and/or accessible

All PEPs should populate and make available the full context of a running operation.

This is currently not being handled consistently.

def pep_resource_create_pre(rule_args, callback, rei):
    callback.writeLine("serverLog", str(rule_args)) 
    print(dir(rule_args[1]))     

produces on an iput:

Sep 16 16:26:11 pid:23542 NOTICE: writeLine: inString = ['demoResc', <irods_types.PluginContext object at 0x7f7636cfac20>, '']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'rule_results']

The <irods_types.PluginContext object at 0x7f7636cfac20> should allow introspection and be holding the information, similar to the iRODS Rule Language *CONTEXT.

wrap irods::query to provide specific query in Python rules

Partially done - see this branch

  • sample core.py in comments of the plugin main .cxx source file
  • now testing with these specific queries active
----
sq1
select group_user_id, user_name from R_USER_GROUP ug inner join R_USER_MAIN u on ug.group_user_id = u.user_id where user_type_name = 'rodsgroup' and ug.user_id = (select user_id from R_USER_MAIN where user_name = 'dan' and user_type_name != 'rodsgroup')
----
sq2arg
select group_user_id, user_name from R_USER_GROUP ug inner join R_USER_MAIN u on ug.group_user_id = u.user_id where user_type_name = 'rodsgroup' and ug.user_id = (select user_id from R_USER_MAIN where user_name = ? and user_type_name != ?)

compiling inside the irods_development_environment (centos7) hangs

I have built the docker environemnt for building the RPMS. It is working well for the base packages, storage_tiering and s3. But it is not building the python rule engine. it seems to hang at the following section:

[ 66%] Building CXX object CMakeFiles/irods_rule_engine_plugin-python.dir/irods_types.cpp.o
/irods_rule_engine_plugin_python/irods_types.cpp:3:9: warning: 'BOOST_SYSTEM_NO_DEPRECATED' macro redefined [-Wmacro-redefined]
#define BOOST_SYSTEM_NO_DEPRECATED BOOST_PYTHON_MAX_ARITY 45
^
:1:9: note: previous definition is here
#define BOOST_SYSTEM_NO_DEPRECATED 1
^
In file included from /irods_rule_engine_plugin_python/irods_types.cpp:7:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/module_init.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:50:
In file included from /usr/include/python2.7/pyconfig.h:6:
/usr/include/python2.7/pyconfig-64.h:1191:9: warning: '_POSIX_C_SOURCE' macro redefined [-Wmacro-redefined]
#define _POSIX_C_SOURCE 200112L
^
/usr/include/features.h:168:10: note: previous definition is here

define _POSIX_C_SOURCE 200809L

     ^

In file included from /irods_rule_engine_plugin_python/irods_types.cpp:7:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/module_init.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:50:
In file included from /usr/include/python2.7/pyconfig.h:6:
/usr/include/python2.7/pyconfig-64.h:1213:9: warning: '_XOPEN_SOURCE' macro redefined [-Wmacro-redefined]
#define _XOPEN_SOURCE 600
^
/usr/include/features.h:170:10: note: previous definition is here

define _XOPEN_SOURCE 700

     ^

In file included from /irods_rule_engine_plugin_python/irods_types.cpp:7:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/module_init.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:151:
In file included from /usr/include/python2.7/Python.h:85:
/usr/include/python2.7/unicodeobject.h:534:5: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
register PyObject obj, / Object */
^~~~~~~~~
/usr/include/python2.7/unicodeobject.h:553:5: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
register PyObject obj / Object */
^~~~~~~~~
/usr/include/python2.7/unicodeobject.h:575:5: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
register const wchar_t w, / wchar_t buffer */
^~~~~~~~~
/usr/include/python2.7/unicodeobject.h:593:5: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
register wchar_t w, / wchar_t buffer */
^~~~~~~~~
In file included from /irods_rule_engine_plugin_python/irods_types.cpp:7:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/module_init.hpp:8:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/prefix.hpp:13:
In file included from /opt/irods-externals/boost1.67.0-0/include/boost/python/detail/wrap_python.hpp:151:
In file included from /usr/include/python2.7/Python.h:94:
/usr/include/python2.7/stringobject.h:173:5: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
register PyObject obj, / string or Unicode object */
^~~~~~~~~
/usr/include/python2.7/stringobject.h:174:5: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
register char *s, / pointer to buffer variable */
^~~~~~~~~
/usr/include/python2.7/stringobject.h:175:5: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
register Py_ssize_t len / pointer to length variable or NULL
^~~~~~~~~

test_irepl_multithreaded fails when python is the default rule engine instance

 --- IrodsSession: icommand executed by [otherrods] [iput largefile.txt] --- 
Assert Command: iput largefile.txt
Expecting EMPTY: ['']
  stdout:
    | 
  stderr:
    | remote addresses: 127.0.0.1 ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: rcvTranHeader: toread = 24, read = 0
    |  ERROR: [-]	/home/rskarbez/software/irods/lib/core/src/procApiRequest.cpp:176:int sendApiRequest(rcComm_t *, int, void *, bytesBuf_t *) :  status [SYS_HEADER_WRITE_LEN_ERR]  errno [Broken pipe] -- message []
    | 	[-]	/home/rskarbez/software/irods/lib/core/src/sockComm.cpp:1258:irods::error sendRodsMsg(irods::network_object_ptr, const char *, bytesBuf_t *, bytesBuf_t *, bytesBuf_t *, int, irodsProt_t) :  status [SYS_HEADER_WRITE_LEN_ERR]  errno [Broken pipe] -- message [failed to call 'write body']
    | 		[-]	/home/rskarbez/software/irods/plugins/network/tcp/libtcp.cpp:355:irods::error tcp_send_rods_msg(irods::plugin_context &, const char *, bytesBuf_t *, bytesBuf_t *, bytesBuf_t *, int, irodsProt_t) :  status [SYS_HEADER_WRITE_LEN_ERR]  errno [Broken pipe] -- message [writeMsgHeader failed]
    | 			[-]	/home/rskarbez/software/irods/lib/core/src/sockComm.cpp:475:irods::error writeMsgHeader(irods::network_object_ptr, msgHeader_t *) :  status [SYS_HEADER_WRITE_LEN_ERR]  errno [Broken pipe] -- message []
    | 				[-]	/home/rskarbez/software/irods/plugins/network/tcp/libtcp.cpp:293:irods::error tcp_write_msg_header(irods::plugin_context &, bytesBuf_t *) :  status [SYS_HEADER_WRITE_LEN_ERR]  errno [Broken pipe] -- message [wrote 0 expected 139]
    | 
    |  ERROR: putUtil: put error for /tempZone/home/otherrods/2016-11-22Z22:49:49--irods-testing-rteRDg/largefile.txt, status = -27000 status = -27000 SYS_COPY_LEN_ERR
Unexpected output on stderr

FAILED TESTING ASSERTION

Port icommands/test/rules into Python to support Python REP in CI

  • nqueens.r
  • rulegenerateBagIt.r
  • ruleintegrityACL.r
  • ruleintegrityAVU.r
  • ruleintegrityAVUvalue.r
  • ruleintegrityDataType.r
  • ruleintegrityExpiry.r
  • ruleintegrityFileOwner.r
  • ruleintegrityFileSize.r
  • rulemsiAclPolicy.r
  • rulemsiAddConditionToGenQuery.r
  • rulemsiAddKeyVal.r
  • rulemsiAddKeyValToMspStr.r
  • rulemsiAddSelectFieldToGenQuery.r
  • rulemsiAddUserToGroup.r
  • rulemsiApplyDCMetadataTemplate.r
  • rulemsiAssociateKeyValuePairsToObj.r
  • rulemsiCheckAccess.r
  • rulemsiCheckHostAccessControl.r
  • rulemsiCheckOwner.r
  • rulemsiCheckPermission.r
  • rulemsiCollCreate.r
  • rulemsiCollectionSpider.r
  • rulemsiCollRepl.r
  • rulemsiCollRsync.r
  • rulemsiCommit.r
  • rulemsiConvertCurrency.r
  • rulemsiCopyAVUMetadata.r
  • rulemsiCreateCollByAdmin.r
  • rulemsiCreateUserAccountsFromDataObj.r
  • rulemsiCreateUser.r
  • rulemsiCreateXmsgInp.r
  • rulemsiDataObjChksum.r
  • rulemsiDataObjClose.r
  • rulemsiDataObjCopy.r
  • rulemsiDataObjCreate.r
  • rulemsiDataObjGet.r
  • rulemsiDataObjLseek.r
  • rulemsiDataObjOpen.r
  • rulemsiDataObjPhymv.r
  • rulemsiDataObjPut.r
  • rulemsiDataObjRead.r
  • rulemsiDataObjRename.r
  • rulemsiDataObjRepl.r
  • rulemsiDataObjRsync.r
  • rulemsiDataObjTrim.r
  • rulemsiDataObjUnlink.r
  • rulemsiDataObjUnlink-trash.r
  • rulemsiDataObjWrite.r
  • rulemsiDeleteCollByAdmin.r
  • rulemsiDeleteDisallowed.r
  • rulemsiDeleteUnusedAVUs.r
  • rulemsiDeleteUser.r
  • rulemsiDeleteUsersFromDataObj.r
  • rulemsiDigestMonStat.r
  • rulemsiDoSomething.r
  • rulemsiExecCmd.r
  • rulemsiExecGenQuery.r
  • rulemsiExecStrCondQuery.r
  • rulemsiExit.r
  • rulemsiExportRecursiveCollMeta.r
  • rulemsiExtractNaraMetadata.r
  • rulemsiExtractTemplateMDFromBuf.r
  • rulemsiFlagDataObjwithAVU.r
  • rulemsiFlagInfectedObjs.r
  • rulemsiFlushMonStat.r
  • rulemsiFreeBuffer.r
  • rulemsiFtpGet.r
  • rulemsiGetAuditTrailInfoByActionID.r
  • rulemsiGetAuditTrailInfoByKeywords.r
  • rulemsiGetAuditTrailInfoByObjectID.r
  • rulemsiGetAuditTrailInfoByTimeStamp.r
  • rulemsiGetAuditTrailInfoByUserID.r
  • rulemsiGetCollectionACL.r
  • rulemsiGetCollectionContentsReport.r
  • rulemsiGetCollectionPSmeta-null.r
  • rulemsiGetCollectionPSmeta.r
  • rulemsiGetCollectionSize.r
  • rulemsiGetContInxFromGenQueryOut.r
  • rulemsiGetDataObjACL.r
  • rulemsiGetDataObjAIP.r
  • rulemsiGetDataObjAVUs.r
  • rulemsiGetDataObjPSmeta.r
  • rulemsiGetDiffTime.r
  • rulemsiGetFormattedSystemTime-human.r
  • rulemsiGetFormattedSystemTime.r
  • rulemsiGetIcatTime.r
  • rulemsiGetMoreRows.r
  • rulemsiGetObjectPath.r
  • rulemsiGetObjType.r
  • rulemsiGetQuote.r
  • rulemsiGetSessionVarValue.r
  • rulemsiGetStderrInExecCmdOut.r
  • rulemsiGetStdoutInExecCmdOut.r
  • rulemsiGetSystemTime.r
  • rulemsiGetTaggedValueFromString.r
  • rulemsiGetUserACL.r
  • rulemsiGetUserInfo.r
  • rulemsiGetValByKey.r
  • rulemsiGoodFailure.r
  • rulemsiGuessDataType.r
  • rulemsiHumanToSystemTime.r
  • rulemsiImageConvert-compression.r
  • rulemsiImageConvert-no-properties.r
  • rulemsiImageConvert.r
  • rulemsiImageGetProperties.r
  • rulemsiIp2location.r
  • rulemsiIsColl.r
  • rulemsiIsData.r
  • rulemsiListEnabledMS.r
  • rulemsiLoadACLFromDataObj.r
  • rulemsiLoadMetadataFromDataObj.r
  • rulemsiLoadMetadataFromXml.r
  • rulemsiLoadUserModsFromDataObj.r
  • rulemsiMakeGenQuery.r
  • rulemsiMakeQuery.r
  • rulemsiMergeDataCopies.r
  • rulemsiNoChkFilePathPerm.r
  • rulemsiNoTrashCan.r
  • rulemsiObjByName.r
  • rulemsiobjget_http.r
  • rulemsiobjget_irods.r
  • rulemsiobjget_slink.r
  • rulemsiobjget_srb.r
  • rulemsiobjget_test.r
  • rulemsiobjget_z3950.r
  • rulemsiobjput_http.r
  • rulemsiobjput_irods.r
  • rulemsiobjput_slink.r
  • rulemsiobjput_srb.r
  • rulemsiobjput_test.r
  • rulemsiobjput_z3950.r
  • rulemsiObjStat.r
  • rulemsiOprDisallowed.r
  • rulemsiPhyBundleColl.r
  • rulemsiPhyPathReg.r
  • rulemsiPrintGenQueryInp.r
  • rulemsiPrintGenQueryOutToBuffer.r
  • rulemsiPrintKeyValPair.r
  • rulemsiPropertiesAdd.r
  • rulemsiPropertiesClear.r
  • rulemsiPropertiesClone.r
  • rulemsiPropertiesExists.r
  • rulemsiPropertiesFromString.r
  • rulemsiPropertiesGet.r
  • rulemsiPropertiesNew.r
  • rulemsiPropertiesRemove.r
  • rulemsiPropertiesSet.r
  • rulemsiPropertiesToString.r
  • rulemsiQuota.r
  • rulemsiRcvXmsg.r
  • rulemsiReadMDTemplateIntoTagStruct.r
  • rulemsiRecursiveCollCopy.r
  • rulemsiRegisterData.r
  • rulemsiRemoveKeyValuePairsFromObj.r
  • rulemsiRenameCollection.r
  • rulemsiRenameLocalZone.r
  • rulemsiRmColl.r
  • rulemsiRollback.r
  • rulemsiSdssImgCutout_GetJpeg.r
  • rulemsiSendMail.r
  • rulemsiSendXmsg.r
  • rulemsiServerMonPerf.r
  • rulemsiSetACL.r
  • rulemsiSetBulkPutPostProcPolicy.r
  • rulemsiSetDataObjAvoidResc.r
  • rulemsiSetDataObjPreferredResc.r
  • rulemsiSetDataTypeFromExt.r
  • rulemsiSetDataType.r
  • rulemsiSetDefaultResc.r
  • rulemsiSetGraftPathScheme.r
  • rulemsiSetMultiReplPerResc.r
  • rulemsiSetNoDirectRescInp.r
  • rulemsiSetNumThreads.r
  • rulemsiSetPublicUserOpr.r
  • rulemsiSetQuota.r
  • rulemsiSetRandomScheme.r
  • rulemsiSetReplComment.r
  • rulemsiSetRescQuotaPolicy.r
  • rulemsiSetRescSortScheme.r
  • rulemsiSetReServerNumProc.r
  • rulemsiSetResource.r
  • rulemsiSleep.r
  • rulemsiSortDataObj.r
  • rulemsiSplitPathByKey.r
  • rulemsiSplitPath.r
  • rulemsiStageDataObj.r
  • rulemsiStoreVersionWithTS.r
  • rulemsiStrArray2String.r
  • rulemsiStrCat.r
  • rulemsiStrchop.r
  • rulemsiString2KeyValPair.r
  • rulemsiString2StrArray.r
  • rulemsiStripAVUs.r
  • rulemsiStrlen.r
  • rulemsiStrToBytesBuf.r
  • rulemsiStructFileBundle.r
  • rulemsiSubstr.r
  • rulemsiSysChksumDataObj.r
  • rulemsiSysMetaModify.r
  • rulemsiSysReplDataObj.r
  • rulemsiTarFileCreate.r
  • rulemsiTarFileExtract.r
  • rulemsiTwitterPost.r
  • rulemsiWriteRodsLog.r
  • rulemsiXmlDocSchemaValidate.r
  • rulemsiXmsgCreateStream.r
  • rulemsiXmsgServerConnect.r
  • rulemsiXmsgServerDisConnect.r
  • rulemsiXsltApply.r
  • rulemsiz3950Submit.r
  • ruleprint_hello.r
  • rulereadXMsg.r
  • ruleTestChangeSessionVar.r
  • rulewriteBytesBuf.r
  • rulewriteKeyValPairs.r
  • rulewriteLine.r
  • rulewritePosInt.r
  • rulewriteString.r
  • rulewriteXMsg.r
  • test_no_memory_error_patch_2242.r
  • testsuite1.r
  • testsuite2.r
  • testsuite3.r
  • testsuiteForLcov.r

make condInput iterable

current required syntax to access the keys and values in a conditional input data structure

def pep_api_data_obj_trim_post(rule_args, callback, rei):
    for i in range(rule_args[2].condInput.len):
        print(str(rule_args[2].condInput.key[i]),str(rule_args[2].condInput.value[i]))

a cleaner syntax might be...

def pep_api_data_obj_trim_post(rule_args, callback, rei):
    for k,v in rule_args[2].condInput.items():
        print(k,v)

should also support iteritems() and viewitems()?

Debian package dependency is missing "python-dev"

When building a deb package, it results in PyExc_SystemError when parsing the core.py. (first line, import datetime)
It appears the package "python-dev" is missing.
In the Cmake file the following line needs to have the package listed:
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${IRODS_PACKAGE_DEPENDENCIES_STRING}, irods-runtime (= ${IRODS_VERSION}), libc6")

But it may also be needed for other packages, so perhaps IRODS_PACKAGE_DEPENDENCIES_STRING should have it.

Invalid pointer free when error occurs inside of callback.msiSetKeyValuePairsToObj

  • main
  • 4-2-stable

Bug Report

iRODS Version, OS and Version

4.2.11 server, 4.2.11.0 plugin

What did you try to do?

Execute a dynamic PEP which calls a microservice from a configured rulebase in PREP (e.g. core.py). The rule looks like this:

def pep_api_touch_pre(rule_args, callback, rei):
    out = callback.msiString2KeyValPair('touch_pre_fired=YES', 0)
    if not out['status']:
        callback.writeLine('stdout', 'ERROR: ' + str(out['code']))
    kvp = out['arguments'][1]
    callback.msiSetKeyValuePairsToObj(kvp, '{0}', '-d') # this should produce an error

This can be triggered by simply executing itouch:

$ itouch foo

Expected behavior

An error code and python stacktrace in the log, like this:

Dec 21 17:00:21 pid:3215 NOTICE: checkAndGetObjectId cmlExecuteNoAnswerSql(rollback) succeeded
Dec 21 17:00:21 pid:3215 NOTICE: rsModAVUMetadata: rcModAVUMetadata failed
Dec 21 17:00:21 pid:3215 remote addresses: 192.168.16.2, 192.168.16.3 ERROR: caught python exception: Traceback (most recent call last):
  File "/etc/irods/core.py", line 337, in pep_api_touch_pre
    callback.msiSetKeyValuePairsToObj(kvp, '{0}', '-d')
RuntimeError: [iRods__Error__Code:-817000] [-]  /irods_source/server/re/include/irods_re_plugin.hpp:326:irods::error irods::dynamic_operation_execution_manager<std::__1::tuple<>, RuleExecInfo *, irods::DONT_AUDIT_RULE>::call(std::string, std::string, OP, As &&...) [T = std::__1::tuple<>, C = RuleExecInfo *, Audit = irods::DONT_AUDIT_RULE, OP = std::__1::function<irods::error (const std::__1::basic_string<char> &, RuleExecInfo *&, irods::unpack &&)>, As = <const std::__1::basic_string<char> &, RuleExecInfo *&, irods::unpack>] :  status [CAT_UNKNOWN_FILE]  errno [] -- message [exec_microservice_adapter failed]
        [-]     /irods_source/server/re/src/irods_re_plugin.cpp:132:irods::error irods::default_microservice_manager<RuleExecInfo *>::exec_microservice_adapter(std::string, irods::default_ms_ctx, std::list<boost::any> &) :  status [CAT_UNKNOWN_FILE]  errno [] -- message [exec_microservice_adapter failed]

Observed behavior (including steps to reproduce, if applicable)

An invalid pointer free kills the connected agent. A sample of the output in the log:

Dec 21 17:29:21 pid:3419 NOTICE: rsModAVUMetadata: rcModAVUMetadata failed
free(): invalid pointer
Caught signal [6]. Dumping stacktrace and exiting

Dumping stack trace
<0>     Offset:         Address: 0x7fe183b8c9b8 /usr/lib/libirods_server.so.4.2.11(+0x15149b8) [0x7fe183b8c9b8]
<1>     Offset:         Address: 0x7fe18095a980 /lib/x86_64-linux-gnu/libpthread.so.0(+0x12980) [0x7fe18095a980]
<2>     Offset:         Address: 0x7fe180595fb7 /lib/x86_64-linux-gnu/libc.so.6(gsignal+0xc7) [0x7fe180595fb7]
<3>     Offset:         Address: 0x7fe180597921 /lib/x86_64-linux-gnu/libc.so.6(abort+0x141) [0x7fe180597921]
<4>     Offset:         Address: 0x7fe1805e0967 /lib/x86_64-linux-gnu/libc.so.6(+0x89967) [0x7fe1805e0967]
<5>     Offset:         Address: 0x7fe1805e79da /lib/x86_64-linux-gnu/libc.so.6(+0x909da) [0x7fe1805e79da]
<6>     Offset:         Address: 0x7fe1805eef0c /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4dc) [0x7fe1805eef0c]
<7>     Offset:         Address: 0x7fe184f82222 /usr/lib/libirods_common.so.4.2.11(clearMsParam+0x92) [0x7fe184f82222]
<8>     Offset:         Address: 0x7fe17ce163b4 /usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so(+0x75f3b4) [0x7fe17ce163b4]
<9>     Offset: 0x76    Address: 0x7fe17ce2c206 boost::python::detail::raw_dispatcher<boost::python::dict (*)(boost::python::tuple const&, boost::python::dict const&)>::operator()(_object*, _object*)
<10>    Offset: 0x34    Address: 0x7fe17ce2c104 boost::python::objects::full_py_function_impl<boost::python::detail::raw_dispatcher<boost::python::dict (*)(boost::python::tuple const&, boost::python::dict const&)>, boost::mpl::vector1<_object*> >::operator()(_object*, _object*)
<11>    Offset: 0x2fb   Address: 0x7fe17c48f85b boost::python::objects::function::call(_object*, _object*) const
<12>    Offset:         Address: 0x7fe17c491ad5 /opt/irods-externals/boost1.67.0-0/lib/libboost_python27.so.1.67.0(+0x25ad5) [0x7fe17c491ad5]
<13>    Offset: 0x47    Address: 0x7fe17c498e87 boost::python::handle_exception_impl(boost::function0<void>)
<14>    Offset:         Address: 0x7fe17c491766 /opt/irods-externals/boost1.67.0-0/lib/libboost_python27.so.1.67.0(+0x25766) [0x7fe17c491766]
<15>    Offset:         Address: 0x7fe17c063913 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fe17c063913]
<16>    Offset:         Address: 0x7fe17c090eec /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x1a1eec) [0x7fe17c090eec]
<17>    Offset:         Address: 0x7fe17c063913 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fe17c063913]
<18>    Offset:         Address: 0x7fe17c00f31a /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x12031a) [0x7fe17c00f31a]
<19>    Offset:         Address: 0x7fe17c063913 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fe17c063913]
<20>    Offset:         Address: 0x7fe17bf8d951 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x41e1) [0x7fe17bf8d951]
<21>    Offset:         Address: 0x7fe17c0ce908 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x7d8) [0x7fe17c0ce908]
<22>    Offset:         Address: 0x7fe17c069649 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x17a649) [0x7fe17c069649]
<23>    Offset:         Address: 0x7fe17c063913 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fe17c063913]
<24>    Offset:         Address: 0x7fe17c0cde37 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_CallObjectWithKeywords+0x47) [0x7fe17c0cde37]
<25>    Offset:         Address: 0x7fe17c03c381 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_CallFunction+0xa1) [0x7fe17c03c381]
<26>    Offset:         Address: 0x7fe17ce1caf4 /usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so(+0x765af4) [0x7fe17ce1caf4]
<27>    Offset:         Address: 0x7fe17ce0e1ca /usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so(+0x7571ca) [0x7fe17ce0e1ca]
<28>    Offset: 0x834   Address: 0x7fe17ce0bb14 exec_rule(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback)
<29>    Offset: 0x141   Address: 0x7fe17ced1b21 irods::error std::__1::__invoke_void_return_wrapper<irods::error>::__call<irods::error (*&)(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback), std::__1::tuple<>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback>(irods::error (*&&&)(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback), std::__1::tuple<>&&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&&&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&&&, irods::callback&&)

<snip>

See the attached log for the full output: prep_invalid_pointer_free.log.txt

Further investigation will be needed, but it is definitely related to fixes introduced for leaks occurring which were discovered in irods/irods#4649.

In particular, the line causing the invalid pointer free - seen in frame <7> - is here, added in 4.2.11.0:

clearMsParam(&msParams.front(), 1);

The issue seems to only manifest itself when a python exception is being thrown (notice frame <13>). When a proper data object path is given to the microservice, an error is not generated and the crash does not occur.

core.py unable to import some Python Standard Library modules

On Ubuntu 18, with PREP 4.3.0.0 installed and configured:
Create an /etc/irods/core.py with one line:

import csv

Any client command such as ils will then cause a crash in the agent, and an error in the /var/log/irods/irods.log to the effect that _Py_NoneStruct cannot be resolved.

Missing <mutex> include

irods_rule_engine_plugin-python.cxx uses std::recursive_mutex and std::lock_guard, but does not #include <mutex>. This can cause errors to be generated during compilation.

spurious data in result when msiGetMoreRows returns CAT_NO_ROWS_FOUND

In RuleCallWrapper::call (irods_rule_engine_plugin-python.cxx:253), an error code of CAT_NO_ROWS_FOUND is ignored. When this occurs with msiGetMoreRows, which is called with an output parameter that contains the previous batch, it will be copied in the result without modification. This will lead to the same batch being reprocessed, followed by a crash on the next call to msiGetMoreRows.

Deadlock in msiDataObjRepl & msiDataObjCopy when called from Python

Tested in 4.2.6 and 4.2.7

When these microservices are called from a PREP rule for data objects larger than
parallel transfer thresholds[1], they do not terminate.

Calling the microservices from the native rule language works without issues.

Example:

def A(rule_args, callback, rei):
    import irods_types
    callback.msiDataObjCopy('/tempZone/home/rods/x.bin',
                            '/tempZone/home/rods/y.bin',
                            'forceFlag=', irods_types.BytesBuf())
$ head -c40M /dev/zero > x.bin
$ iput -f x.bin
$ irule A null null
... (hung)

ps output indicates the responsible agent is waiting on a futex:

$ ps -lq 4995
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
1 S   997  4995  4164  0  80   0 - 259245 futex_ ?       00:00:00 irodsServer

Killing the agent produces an interesting stacktrace[2], which points to a
spawned data transfer/copy thread sameHostPartialCopy(), created by
sameHostCopy(), that does not terminate (join in the main agent thread
hangs forever).

Apparently, in #1, a recursive mutex was introduced to prevent concurrent PREP
access across parallel transfer threads.
This change allowed multiple threads to safely trigger Python PEP rules
sequentially, but, if I understand correctly, it did not take into account that
the PREP may already be held hostage by a Python rule on a different thread
(i.e. the rule that triggered the transfer by calling an msi).

So we now have a deadlock: The spawned sameHostPartialCopy thread wants to
execute a PEP rule and is waiting for access to the PREP, while the thread
holding the PREP mutex is waiting for that spawned thread to finish (in
sameHostCopy).

As expected in this case, creating dummy implementations[3] of all static and
dynamic PEPs in the native rule language (which must then also be specified
before the prep in the server config) bypasses this issue, as the PREP no
longer needs to be consulted for PEPs during parallel transfer threads.
This is not really a usable workaround.

[1]

>= transfer_buffer_size_for_parallel_transfer_in_megabytes =4M (?) for msiDataObjRepl
> maximum_size_for_single_buffer_in_megabytes =32M for msiDataObjCopy

[2]

irodsServer: /tmp/irods_externals6CFhcy/clang3.8-0_src/llvm/projects/libcxx/src/mutex.cpp:86: std::__1::recursive_mutex::~recursive_mutex(): Assertion `e == 0' failed.
Caught signal [6]. Dumping stacktrace and exiting

Dumping stack trace
<0>	Offset:      	Address: 0x7f8d4218da0c	/lib/libirods_server.so.4.2.7(+0xb90a0c) [0x7f8d4218da0c]
<1>	Offset:      	Address: 0x7f8d3f84d5f0	/lib64/libpthread.so.0(+0xf5f0) [0x7f8d3f84d5f0]
<2>	Offset:      	Address: 0x7f8d3e55f337	/lib64/libc.so.6(gsignal+0x37) [0x7f8d3e55f337]
<3>	Offset:      	Address: 0x7f8d3e560a28	/lib64/libc.so.6(abort+0x148) [0x7f8d3e560a28]
<4>	Offset:      	Address: 0x7f8d3e558156	/lib64/libc.so.6(+0x2f156) [0x7f8d3e558156]
<5>	Offset:      	Address: 0x7f8d3e558202	/lib64/libc.so.6(+0x2f202) [0x7f8d3e558202]
<6>	Offset:      	Address: 0x7f8d3eb5c8e1	/opt/irods-externals/clang-runtime3.8-0/lib/libc++.so.1(+0x4f8e1) [0x7f8d3eb5c8e1]
<7>	Offset:      	Address: 0x7f8d3e562c99	/lib64/libc.so.6(+0x39c99) [0x7f8d3e562c99]
<8>	Offset:      	Address: 0x7f8d3e562ce7	/lib64/libc.so.6(+0x39ce7) [0x7f8d3e562ce7]
<9>	Offset:      	Address: 0x7f8d421aab77	/lib/libirods_server.so.4.2.7(+0xbadb77) [0x7f8d421aab77]
<10>	Offset:      	Address: 0x7f8d3e55f3b0	/lib64/libc.so.6(+0x363b0) [0x7f8d3e55f3b0]
<11>	Offset:      	Address: 0x7f8d3f8499f3	/lib64/libpthread.so.0(pthread_cond_wait+0xc3) [0x7f8d3f8499f3]
<12>	Offset: 0x3b 	Address: 0x42988b	boost::condition_variable::wait(boost::unique_lock<boost::mutex>&)
<13>	Offset: 0x66 	Address: 0x7f8d40ce8586	boost::thread::join_noexcept()
<14>	Offset: 0x502	Address: 0x7f8d42196d02	sameHostCopy(rsComm_t*, DataCopyInp*)
<15>	Offset: 0x5b 	Address: 0x7f8d41eb9d9b	_rsDataCopy(rsComm_t*, DataCopyInp*)
<16>	Offset: 0x3ac	Address: 0x7f8d41ed132c	dataObjCopy(rsComm_t*, int)
<17>	Offset: 0x222	Address: 0x7f8d41ec11f2	_rsDataObjCopy(rsComm_t*, int, int, transferStat_t**)
<18>	Offset: 0x250	Address: 0x7f8d41ec0960	rsDataObjCopy(rsComm_t*, DataObjCopyInp*, transferStat_t**)
<19>	Offset: 0xca 	Address: 0x7f8d4231933a	msiDataObjCopy(MsParam*, MsParam*, MsParam*, MsParam*, RuleExecInfo*)
<20>	Offset: 0x19b	Address: 0x7f8d422d4aab	int irods::ms_table_entry::call_handler<MsParam*, MsParam*, MsParam*, MsParam*, RuleExecInfo*>(MsParam*, MsParam*, MsParam*, MsParam*, RuleExecInfo*)
<21>	Offset: 0x274	Address: 0x7f8d422db9c4	irods::default_microservice_manager<RuleExecInfo*>::exec_microservice_adapter(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, RuleExecInfo*, std::__1::list<boost::any, std::__1::allocator<boost::any> >&)
<22>	Offset: 0x74 	Address: 0x7f8d422e4194	irods::error irods::default_microservice_manager<RuleExecInfo*>::exec_microservice<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, RuleExecInfo*, irods::unpack&&)
<23>	Offset: 0x45 	Address: 0x7f8d422e40a5	std::__1::__function::__func<irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::operator()(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&) const::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&), std::__1::allocator<irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::operator()(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&) const::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&)>, irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&)>::operator()(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&)
<24>	Offset: 0xfe 	Address: 0x7f8d422e447e	irods::error irods::dynamic_operation_execution_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)1>::call<std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&&&, RuleExecInfo*&&&, irods::unpack&&)::'lambda'()::operator()() const
<25>	Offset: 0x9f 	Address: 0x7f8d422e3e3f	irods::error irods::dynamic_operation_execution_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)1>::call<std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, RuleExecInfo*&, irods::unpack&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&&&, RuleExecInfo*&&&, irods::unpack&&)
<26>	Offset: 0x103	Address: 0x7f8d422e2e93	irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::operator()(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&) const
<27>	Offset: 0x23c	Address: 0x7f8d422e2b1c	irods::error irods::control<irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::'lambda'(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&), irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&), std::__1::tuple<>, irods::unpack>(std::__1::list<irods::re_pack_inp<std::__1::tuple<> >, std::__1::allocator<irods::re_pack_inp<std::__1::tuple<> > > >&, irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::'lambda'(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&), irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)
<28>	Offset: 0x1d4	Address: 0x7f8d3b915ba4	irods::error irods::callback::operator()<irods::unpack>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::unpack&&)
<29>	Offset:      	Address: 0x7f8d3b90f54a	/usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so(+0x2b454a) [0x7f8d3b90f54a]
<30>	Offset: 0x3a 	Address: 0x7f8d3b9155ba	boost::python::detail::raw_dispatcher<boost::python::dict (*)(boost::python::tuple const&, boost::python::dict const&)>::operator()(_object*, _object*)
<31>	Offset: 0x37a	Address: 0x7f8d3b43218a	boost::python::objects::function::call(_object*, _object*) const
<32>	Offset:      	Address: 0x7f8d3b4343c5	/opt/irods-externals/boost1.60.0-0/lib/libboost_python.so.1.60.0(+0x293c5) [0x7f8d3b4343c5]
<33>	Offset: 0x4d 	Address: 0x7f8d3b43a59d	boost::python::handle_exception_impl(boost::function0<void>)
<34>	Offset:      	Address: 0x7f8d3b43406a	/opt/irods-externals/boost1.60.0-0/lib/libboost_python.so.1.60.0(+0x2906a) [0x7f8d3b43406a]
<35>	Offset:      	Address: 0x7f8d3ae7dab3	/lib64/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7f8d3ae7dab3]
<36>	Offset:      	Address: 0x7f8d3ae8caa5	/lib64/libpython2.7.so.1.0(+0x5aaa5) [0x7f8d3ae8caa5]
<37>	Offset:      	Address: 0x7f8d3ae7dab3	/lib64/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7f8d3ae7dab3]
<38>	Offset:      	Address: 0x7f8d3aed4e77	/lib64/libpython2.7.so.1.0(+0xa2e77) [0x7f8d3aed4e77]
<39>	Offset:      	Address: 0x7f8d3ae7dab3	/lib64/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7f8d3ae7dab3]
<40>	Offset:      	Address: 0x7f8d3af12286	/lib64/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x2336) [0x7f8d3af12286]
<41>	Offset:      	Address: 0x7f8d3af1908d	/lib64/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x7ed) [0x7f8d3af1908d]
<42>	Offset:      	Address: 0x7f8d3aea29c8	/lib64/libpython2.7.so.1.0(+0x709c8) [0x7f8d3aea29c8]
<43>	Offset:      	Address: 0x7f8d3ae7dab3	/lib64/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7f8d3ae7dab3]
<44>	Offset:      	Address: 0x7f8d3af0f947	/lib64/libpython2.7.so.1.0(PyEval_CallObjectWithKeywords+0x47) [0x7f8d3af0f947]
<45>	Offset:      	Address: 0x7f8d3af2fed7	/lib64/libpython2.7.so.1.0(PyEval_CallFunction+0xb7) [0x7f8d3af2fed7]
<46>	Offset:      	Address: 0x7f8d3b90aaa3	/usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so(+0x2afaa3) [0x7f8d3b90aaa3]
<47>	Offset: 0x385	Address: 0x7f8d3b909a15	exec_rule(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback)
<48>	Offset: 0x2e 	Address: 0x7f8d3b94a31e	std::__1::__function::__func<irods::error (*)(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback), std::__1::allocator<irods::error (*)(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback)>, irods::error (std::__1::tuple<>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback)>::operator()(std::__1::tuple<>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback&&)

[3] https://gist.github.com/cjsmeele/dfb029048e7a31643acd04d8eb200e96
(assumes core.re already contains all static PEP rules)

Change to python 3

  • Python 2 has end-of-life scheduled for the end of 2019, so we should stop depending on it and move to python 3 sometime in the next year.

  • Need to remember to remove the removal of register around boost::python:

#define register
...
#undef register

In plugin package installations, irods-owned paths may become root-owned

  • 4-2-stable
  • master

Bug Report

iRODS Version, OS and Version

iRODS 4.2.9 + Python REP 4.2.9.0 (just pre-release) on Centos 7
BUT this may apply to many other plugins, for all we know....

What did you try to do?

Install an iRODS plugin ( in this case the Python rule engine plugin ) RPM that writes files to /etc/irods or /var/lib/irods ...

Expected behavior

These directories should remain owned by irods service account user.

Observed behavior (including steps to reproduce, if applicable)

The directories become root-owned, preventing the irods user from being able to create new files within them. (As hinted, this was first discovered while running Python REP tests on Centos 7).

Explanation:

Because of a snag in CMake RPM defaults, whenever files are installed from a package, the paths "above" them are also marked as install targets.

Exiting with code -808000 does not actually stop code execution

Tested in 4.2.6 and 4.2.11

When you use 'msiExit' to try and exit out of python rule engine execution, the execution is not stopped.

Example:

@make(inputs=[], outputs=[], handler=Output.STORE)
def test_rule(ctx):
    # -808000 CAT_NO_ROWS_FOUND
    ctx.callback.msiExit("-808000", "Rows not found")
    ctx.callback.writeLine("stdout", "This should not appear")
def main(rule_args, callback, rei):
    output = callback.test_rule()


INPUT null
OUTPUT ruleExecOut
irods@irods:/rules$ irule -r irods_rule_engine_plugin-python-instance -F /rules/tests/run_test_rule.r
This should not appear
Level 0: Rows not found

irods@irods:/rules$

This issue only seems to appear (as far as we know) with code "-808000". When using "-808001" it does actually exit out.
Is this behavior intentional?

Boost.Python 1.67 needs version-agnostic symbolic link

This repository presently offers two versions of the Boost header libraries, 1.60 and 1.67.

Unlike version 1.60 however, Boost.Python 1.67 does not include the symbolic link "sans version" in the lib subdirectory for e.g. plugins that might want to link against it using the option -lboost_python. This recently helped to cause a delay in building/testing of Python RE Plugin against iRODS master at 4.3.0, which was attained in the end but required two corrections:

  • forge the required sym-link in the /opt/irods-externals/boost1.67.0-0/lib directory
  • CMakeLists.txt mods, see #19 in Python RE Plugin

Specifically the issue is that whereas in 1.60 we have:

libboost_python.so -> libboost_python.so.1.60.0

.... but, in 1.67 , we're missing the corresponding symbolic link. This causes failures in building and testing the Python Rule Engine against the iRODS 4.3.0 runtime at the bench as well as presumably also in Continuous Integration

replication from compound using python

Bug Report

Irods version 4.2.11, centos7

I have the following resource hierarchy (OldResource being an old resource that I want to migrate data from)

DiskResource:unixfilesystem
OldResource:compound
โ”œโ”€โ”€ OldArchiveResource:univmss
โ””โ”€โ”€ OldCacheResource:unixfilesystem

Data is only in the archive, the cache is empty.

I've written a custom rule that manages replication since it is a lengthy operation that I need to manage myself

migrateOneObj.r content:

main {
    testReplicationFromCompound();
}
INPUT null
OUTPUT ruleExecOut

core.re content:

testReplicationFromCompound {
    msiDataObjRepl("/zone/file.zip",
        "rescName=OldResource++++backupRescName=DiskResource", *Status);
}

When I run irule -F migrateOneObj.r under the user that owns file.zip, it works correctly.

However, if I move the function testReplicationFromCompound to python (core.py):

def testReplicationFromCompound(rule_args, callback, rei):
    callback.msiDataObjRepl("/zone/file.zip",
        "rescName=OldResource++++backupRescName=DiskResource", 0)

and run irule -F migrateOneObj.r (under the user that owns file.zip) the following happens:

  • the operation blocks on retrieving data from archive and never finishes
  • there are 2 irodsServer processes, that started when irule was started. strace says that
    • first is blocked on read from a pipe
    • second (child of the previous one) is blocked on futex(0x7f85e89d8ec8, FUTEX_WAIT_PRIVATE, 2, NULL
  • rodsLog's last line is
    Jan 17 12:52:03 pid:88 NOTICE: execCmd:../../var/lib/irods/msiExecCmd_bin/migration- 
    interface.sh argv:stageToCache '/data/archive/dev/file.zip' '/data/cache/dev/file.zip
    
  • univmss driver (shell script migration-interface.sh) is never run (otherwise it would create an entry in a custom log file)
  • there is an empty file created in the cache resource vault
  • in the sql db there are 2 rows:
    • first one corresponds to the archive replica (data_is_dirty = 4)
    • second one corresponds to the cache replica (data_is_dirty = 2)

msiExecCmd not usable from Python Rules

msiExecCmd should be callable from rules written for the PREP (Python rule engine plugin), similarly as from rules in iRODS's native rule language.

Currently, however, the following rule will abort on the call to the msiExecCmd microservice when run from /etc/irods/core.py :

import os ,  irods_types
def myTestRule(rule_args, callback, rei):
    #source_file = global_vars['*SourceFile'][1:-1]
    source_file = '/tempZone/home/rods/VERSION.json'
    import os
    (coll, filen) = os.path.split(source_file)
    ret_val = callback.msiObjStat(source_file, irods_types.RodsObjStat())
    source_file_stat = ret_val['arguments'][1]
    ret_val = callback.msiExecCmd( "hello", "a b", "null", "null", "null", irods_types.ExecCmdOut() );
    ret_val = callback.msiObjStat(coll, irods_types.RodsObjStat())
    coll_stat = ret_val['arguments'][1]
    callback.writeLine('serverLog', 'Type of object is written into a RodsObjStat_PI structure')

Note the iRODS data object /tempZone/home/rods/VERSION.json should exist before attempting to call myTestRule ; and the call can be done from a ".r" file with no arguments.
The attempted execution of the above rule function produces this error output in the rodsLog :

Jul 12 15:30:36 pid:1481 NOTICE: writeLine: inString = Type of object is written into a RodsObjStat_PI structure
Jul 12 15:57:26 pid:3742 remote addresses: 127.0.0.1, 152.54.8.225 ERROR: caught python exception: Traceback (most recent call last):
  File "/etc/irods/core.py", line 15, in myTestRule
    ret_val = callback.msiExecCmd( "hello", "a b", "null", "null", "null", irods_types.ExecCmdOut() );
RuntimeError: iRODS Exception:
    file: /home/dmoore/github/irods_rule_engine_plugin_python/irods_rule_engine_plugin-python.hpp
    function: msParam_t (anonymous namespace)::msParam_from_object_impl(boost::python::object &)
    line: 117
    code: -66000
    message:
        Attempted to extract a boost::python::object containing a non-conforming type
<< stack trace follows >>

The presence of the msiExecCmd in the above Python rule is just for demonstration, to show contrast with an analogous call to a different microservice msiObjStat, which is similar in pattern and superficial purpose to the failed microservice call.

If the offending line of code is reduced to contain only the python expression irods_types.ExecCmdOut() , or if it is commented out entirely, the rule will complete its execution, showing that it is the actual call to msiExecCmd that triggers the error in question, rather than the act of instantiating the python class irods_types.ExecCmdOut . One will then see the expected output in the rodsLog :

Jul 12 15:30:36 pid:1481 NOTICE: writeLine: inString = Type of object is written into a RodsObjStat_PI structure

Note also, when we run the native rule-engine version of the msiExecCmd call that failed above, with identical (or as closely corresponding as possible) arguments:

myTestNativeRule
{
    msiExecCmd( "hello", "a b", "null", "null", "null", *OUT );
}

we get the expected behavior of:

Jul 12 16:00:51 pid:4060 NOTICE: execCmd:../../var/lib/irods/msiExecCmd_bin/hello argv:a b

Python 2.7 libraries use incompatible 'register' keyword

C++17 removes the register keyword, and the headers for python 2.7 make use of that keyword. Recommended solution is to #define register before the include and #undef register afterwards. This is sort of a hack, but there is no other option without shipping our own edited python headers and it should be safe since register is an ignored keyword in C, and the python headers are written in C. This is also a stopgap measure until we start shipping with python 3, given that python 2 end-of-life is scheduled for late 2019.

Build fails, find_package(IRODS 4.3.0 REQUIRED) in CMakeList.txt

The build fails, because no iRODS 4.3.0 can be found.

CMake Error at CMakeLists.txt (find_package):", " Could not find a configuration file for package \"IRODS\" that is compatible", " with requested version \"4.3.0\".", "", " The following configuration files were considered but not accepted:", "", " /usr/lib/irods/cmake/IRODSConfig.cmake, version: 4.2.0"

Build fails with non-constant-expression cannot be narrowed from type 'int' to 'char'

Hello
I am trying to deploy irods python rule engine for iRODS 4.2.5.
when I send make package command I get the following error:

/home/ubuntu/irods_rule_engine_plugin_python/irods_types.cpp:572:30: note: in instantiation of function template specialization 'make_init_function<rodsEnv, char [64], char [64], int, char [1088], char [1088], char [64], char [64], char
[64], int, char [256], char [64], char [256], char [256], int, int, int, char [128], char [64], char [64], char [1088], char [1088], char [1088], char [1088], char [1088], char [1088], char [1088], int, int, char [128], int, int,
int, char [1088]>' requested here
.def("init", make_init_function(
^
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/ubuntu/irods_rule_engine_plugin_python/init_struct.hpp:60:20: note: insert an explicit cast to silence this issue
new T{ populate_helper(args, index, iter, index_into_array)... }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_cast( )
4 warnings and 9 errors generated.
CMakeFiles/irods_rule_engine_plugin-python.dir/build.make:86: recipe for target 'CMakeFiles/irods_rule_engine_plugin-python.dir/irods_types.cpp.o' failed
make[2]: *** [CMakeFiles/irods_rule_engine_plugin-python.dir/irods_types.cpp.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/irods_rule_engine_plugin-python.dir/all' failed
make[1]: *** [CMakeFiles/irods_rule_engine_plugin-python.dir/all] Error 2
Makefile:149: recipe for target 'all' failed
make: *** [all] Error 2

Best regards
Mohamad

Install dependencies for building the plugin

Maybe interesting for documentation or other people:
On EL7, I first had to install these dependencies before i was able to build the plugin:
irods-externals* irods-devel gcc-c++ python-devel openssl-devel rpm-build

I also had to use the cmake of irods-externals-cmake, not the distro cmake, so I did run /opt/irods-externals/cmake3.5.2-0/bin/cmake ../ instead of just cmake ../

PREP does not support continuations

  • master
  • 4-2-stable

Feature Request

exec_rule, exec_rule_text, and exec_rule_expression do not support anything other than returning zero on success. To support continuation, these functions need to allow rules to pass different codes back to the REPF.



These lines need to be changed to CODE(RULE_ENGINE_CONTINUE). That would give other REPs a chance to handle the PEP.

Workaround

Keep all of a rule's functionality under a single REP. Do not split it across REPs (e.g. part of the rule is in the native rule engine while the rest of the rule is in the python rule engine).

allow rodsuser to run a rule string

The command:

irule -r irods_rule_engine_plugin-python-instance python_rule null  null

should succeed if executed by a rodsuser.
In this context, the command line argument python_rule should be taken as the identifier of a python function (a rule) defined in the global namespace of /etc/irods/core.py.
Currently this command only succeeds for a rodsadmin. A rodsuser gets the errorSYS_NO_API_PRIV.

exec_rule_text, exec_rule_expression not importing core

bp::object core_module = bp::import("core");

Means that e.g. delay rules can't immediately use functions in core.py. Haven't tried putting import core in the rule, that may be a workaround.

Perhaps this is desired? I'm not sure what the consequences of using an import statement within a rule are. Would a module imported in one call to exec_rule be available in a later call to exec_rule_text within the same agent?

PluginContext objects' map() method crashes in some PEPs

Some PEPs allow access to the fields of a rule argument of type irods_types.PluginContext via the object's map( ) method, whereas in other PEP's calling this method crashes the agent .

In pep_resource_create_post, this works without apparent flaws:
With this rule in core.py:

def  ( rule_args, callback, rei ):
    print ('map',repr(rule_args[1].map()))

an iput will print context fields from the returned python dict object:

('map', "{'proxy_auth_info_auth_scheme': '', 'auth_scheme': 'native', 'logical_path': '/tempZone/home/rods/dotdot.py', 'physical_path': '/var/lib/irods/Vault/home/rods/dotdot.py', 'proxy_auth_info_host': '', 'proxy_auth_info_ppid': '0', 'proxy_auth_info_auth_str': '', 'flags_kw': '3', 'proxy_user_other_info_user_modify': '', 'file_size': '0', 'proxy_auth_info_auth_flag': '5', 'proxy_rods_zone': 'tempZone', 'user_sys_uid': '0', 'in_pdmo': '', 'user_user_other_info_user_comments': '', 'proxy_user_other_info_user_info': '', 'user_user_name': 'rods', 'user_user_other_info_user_create': '', 'mode_kw': '384', 'user_auth_info_ppid': '0', 'user_auth_info_host': '', 'l1_desc_idx': '-1', 'user_auth_info_auth_scheme': '', 'proxy_user_name': 'rods', 'proxy_user_other_info_user_create': '', 'user_user_other_info_user_modify': '', 'proxy_user_type': '', 'file_descriptor': '10', 'dataType': '', 'user_auth_info_flag': '0', 'proxy_sys_uid': '0', 'user_user_other_info_user_info': '', 'user_rods_zone': 'tempZone', 'user_user_type': '', 'dataId': '0', 'user_auth_info_auth_flag': '5', 'resc_hier': 'demoResc', 'proxy_user_other_info_user_comments': '', 'client_addr': '127.0.0.1', 'proxy_auth_info_flag': '0', 'repl_requested': '-1', 'user_auth_info_auth_str': ''}")

But in, for example, pep_api_data_obj_put_post,

def pep_api_data_obj_put_post ( rule_args, callback, rei ):
    print ('map',repr(rule_args[1].map()))

The same iput statement triggers a crash with this stacktrace in the logs:

Caught signal [11]. Dumping stacktrace and exiting

Dumping stack trace
<0>     Offset:         Address: 0x7f243aa2f123 /usr/lib/libirods_server.so.4.2.8(+0xd64123) [0x7f243aa2f123]
<1>     Offset:         Address: 0x7f2437173390 /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390) [0x7f2437173390]
<2>     Offset:         Address: 0x7f24358c3840 /usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so(+0x4ae840) [0x7f24358c3840]
<3>     Offset: 0x5f    Address: 0x7f2435d4669f boost::python::objects::caller_py_function_impl<boost::python::detail::caller<boost::python::dict (*)(irods::plugin_context*), boost::python::default_call_policies, boost::mpl::vector2<boost::python::dict, irods::plugin_context*> > >::operator()(_object*, _object*)
<4>     Offset: 0x2fb   Address: 0x7f24351ec8eb boost::python::objects::function::call(_object*, _object*) const
<5>     Offset:         Address: 0x7f24351eeb65 /opt/irods-externals/boost1.67.0-0/lib/libboost_python27.so.1.67.0(+0x25b65) [0x7f24351eeb65]
<6>     Offset: 0x47    Address: 0x7f24351f5f17 boost::python::handle_exception_impl(boost::function0<void>)
<7>     Offset:         Address: 0x7f24351ee7f6 /opt/irods-externals/boost1.67.0-0/lib/libboost_python27.so.1.67.0(+0x257f6) [0x7f24351ee7f6]
<8>     Offset:         Address: 0x7f2434b3f2b3 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7f2434b3f2b3]
<9>     Offset:         Address: 0x7f2434add39c /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x543c) [0x7f2434add39c]
<10>    Offset:         Address: 0x7f2434c1611c /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x85c) [0x7f2434c1611c]
<11>    Offset:         Address: 0x7f2434b6c3b0 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x13e3b0) [0x7f2434b6c3b0]
<12>    Offset:         Address: 0x7f2434b3f2b3 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7f2434b3f2b3]
<13>    Offset:         Address: 0x7f2434c15547 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_CallObjectWithKeywords+0x47) [0x7f2434c15547]
<14>    Offset:         Address: 0x7f2434b814e7 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_CallFunction+0xb7) [0x7f2434b814e7]
<15>    Offset:         Address: 0x7f24356e6ae1 /usr/lib/irods/plugins/rule_engines/libirods_rule_engine_plugin-python.so(+0x2d1ae1) [0x7f24356e6ae1]
<16>    Offset: 0x33a   Address: 0x7f24356e542a exec_rule(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback)
<17>    Offset: 0x2e    Address: 0x7f243572bf7e std::__1::__function::__func<irods::error (*)(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback), std::__1::allocator<irods::error (*)(std::__1::tuple<> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback)>, irods::error (std::__1::tuple<>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback)>::operator()(std::__1::tuple<>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::list<boost::any, std::__1::allocator<boost::any> >&, irods::callback&&)
<18>    Offset: 0xf6    Address: 0x7f243a8bcd76 irods::error irods::pluggable_rule_engine<std::__1::tuple<> >::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::tuple<>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&, irods::callback)
<19>    Offset: 0x85    Address: 0x7f243a8bcc05 std::__1::__function::__func<irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::operator()(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&) const::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&), std::__1::allocator<irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::operator()(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&) const::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)>, irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)>::operator()(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)
<20>    Offset: 0x197   Address: 0x7f243a8bd7c7 irods::error irods::dynamic_operation_execution_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)1>::call<std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&&&, irods::re_pack_inp<std::__1::tuple<> >&&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'()::operator()() const
<21>    Offset: 0xce    Address: 0x7f243a8bc89e irods::error irods::dynamic_operation_execution_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)1>::call<std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::function<irods::error (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&&&, irods::re_pack_inp<std::__1::tuple<> >&&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)
<22>    Offset: 0x103   Address: 0x7f243a8bc473 irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::operator()(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&) const
<23>    Offset: 0x100   Address: 0x7f243a8bc0f0 irods::error irods::control<irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&), irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&), std::__1::tuple<>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::list<irods::re_pack_inp<std::__1::tuple<> >, std::__1::allocator<irods::re_pack_inp<std::__1::tuple<> > > >&, irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'(irods::re_pack_inp<std::__1::tuple<> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&), irods::error irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>::exec_rule<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*, BytesBuf*, portalOprOut**>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)::'lambda'(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, irods::plugin_context&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&), std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&&, irods::plugin_context&&&, DataObjInp*&&, BytesBuf*&&, portalOprOut**&&)
<24>    Offset: 0x629   Address: 0x7f243a8bbb89 irods::error irods::api_entry::invoke_policy_enforcement_point<DataObjInp*, BytesBuf*, portalOprOut**>(irods::rule_engine_context_manager<std::__1::tuple<>, RuleExecInfo*, (irods::rule_execution_manager_pack)0>, irods::plugin_context, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, DataObjInp*, BytesBuf*, portalOprOut**)
<25>    Offset: 0xe67   Address: 0x7f243a7b0257 int irods::api_entry::call_handler<DataObjInp*, BytesBuf*, portalOprOut**>(rsComm_t*, DataObjInp*, BytesBuf*, portalOprOut**)
<26>    Offset: 0x73a   Address: 0x7f243aa6177a rsApiHandler(rsComm_t*, int, BytesBuf*, BytesBuf*)
<27>    Offset: 0xa4b   Address: 0x7f243aa6381b readAndProcClientMsg(rsComm_t*, int)
<28>    Offset: 0xd08   Address: 0x7f243aa54738 agentMain(rsComm_t*)
<29>    Offset: 0x1fa5  Address: 0x7f243aa52985 runIrodsAgentFactory(sockaddr_un)
<30>    Offset:         Address: 0x42706d       /usr/sbin/irodsServer(main+0x4cd) [0x42706d]
<31>    Offset:         Address: 0x7f2436db8830 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f2436db8830]
<32>    Offset:         Address: 0x426ac9       /usr/sbin/irodsServer(_start+0x29) [0x426ac9]

Jul 27 13:16:46 pid:1340  ERROR: Agent process [17146] exited with status [11]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.