def test_rulefile_in_file_like_object_2__336(self): rule_file_contents = textwrap.dedent("""\ main { other_rule() writeLine("stdout","["++type(*msg2)++"][*msg2]"); } other_rule { writeLine("stdout","["++type(*msg1)++"][*msg1]"); } INPUT *msg1="",*msg2="" OUTPUT ruleExecOut """) r = Rule(self.sess, rule_file=io.BytesIO(rule_file_contents.encode('utf-8'))) output = r.execute() lines = self.lines_from_stdout_buf(output) self.assertRegexpMatches(lines[0], '\[STRING\]\[\]') self.assertRegexpMatches(lines[1], '\[STRING\]\[\]') r = Rule(self.sess, rule_file=io.BytesIO(rule_file_contents.encode('utf-8')), params={ '*msg1': 5, '*msg2': '"A String"' }) output = r.execute() lines = self.lines_from_stdout_buf(output) self.assertRegexpMatches(lines[0], '\[INTEGER\]\[5\]') self.assertRegexpMatches(lines[1], '\[STRING\]\[A String\]')
def test_set_metadata_288(self): session = self.sess # rule body rule_body = textwrap.dedent('''\ *attribute.*attr_name = "*attr_value" msiAssociateKeyValuePairsToObj(*attribute, *object, "-d") # (: -- just a comment -- :) writeLine("serverLog","*value") ''') input_params = { '*value': "3334", "*object": '/tempZone/home/rods/runner.py', '*attr_name': 'XX', '*attr_value': 'YY' } output = 'ruleExecOut' myrule = Rule(session, body=rule_body, params=input_params, output=output) myrule.execute()
def rule_open(self): logger.info("Rule open") rule_body = "do_openProjectCollection {" \ "{openProjectCollection('" + self.projectID + "', '" + self.collectionID + "', 'rods', 'own');}" \ "}" open_rule = Rule(self.session, body=rule_body) open_rule.execute()
def rule_close(self): logger.info("Rule close") rule_body = "do_closeProjectCollection {" \ "{closeProjectCollection('" + self.projectID + "', '" + self.collectionID + "');}}" close_rule = Rule(self.session, body=rule_body) close_rule.execute()
def ruleRegistration(self, object_path, target_path, rule_path): # check connection self._irodsConnect() self.log.info( "exec Registration Remote replicated object inside irods ") # load rule from file rule_total = self.load_rule( rule_path, source='"{object_path}"'.format(**locals()), destination='"{target_path}"'.format(**locals())) # prep rule myrule = Rule(self.session, body=rule_total['body'], params=rule_total['params'], output=rule_total['output']) # exec rule try: myrule.execute() # check that metadata is there #returnedMeta = self.session.metadata.get(DataObject, object_path) self.log.info(" REGISTRATION for digitalObject: " + object_path + " is: OK") except Exception as ex: self.log.info("Could not execute a rule for REGISTRATION ") self.log.info(ex) pass return 1 #returnedMeta
def rulePIDsingle(self, object_path, rule_path): # check connection self._irodsConnect() self.log.info("exec PID SINGLE rule inside irods ") # load rule from file rule_total = self.load_rule(rule_path, path='"{object_path}"'.format(**locals())) # prep rule myrule = Rule(self.session, body=rule_total['body'], params=rule_total['params'], output=rule_total['output']) # exec rule try: myrule.execute() # check that metadata is there #returnedMeta = self.session.metadata.get(DataObject, object_path) self.log.info(" PID for digitalObject: " + object_path + " is: OK") except Exception as ex: self.log.info("Could not execute a rule for PID ") self.log.info(ex) pass return 1 #returnedMeta
def main(): module = AnsibleModule(argument_spec=dict(groupName=dict(default=None, required=True), user=dict(default=None, required=True), role=dict(default=None, required=True), state=dict(default="present")), supports_check_mode=True) groupName = module.params["groupName"] user = module.params["user"] role = module.params["role"] state = module.params["state"] if IRODSCLIENT_AVAILABLE: try: session, ienv = get_session() except iRODSException: module.fail_json( msg= "Could not establish irods connection. Please check ~/.irods/irods_environment.json" ) else: module.fail_json(msg="python-irodsclient needs to be installed") changed = False # Rule to add an user to a group in Yoda. rule_body = textwrap.dedent('''\ test {{ uuGroupUserAdd(*groupName, *user, *status, *message); uuGroupUserChangeRole(*groupName, *user, *role, *status, *message); }}''') # Rule parameters. input_params = { '*groupName': '"{groupName}"'.format(**locals()), '*user': '******'.format(**locals()), '*role': '"{role}"'.format(**locals()) } output = 'ruleExecOut' # Execute rule. if not module.check_mode: myrule = Rule(session, body=rule_body, params=input_params, output=output) myrule.execute() changed = True module.exit_json(changed=changed, irods_environment=ienv)
def test_add_metadata_from_rule(self): ''' Runs a rule whose body and input parameters are created in our script. The rule adds metadata attributes to an iRODS object and we check for the presence of said attributes. ''' session = self.sess # test metadata attr_name = "test_attr" attr_value = "test_value" # make test object ts = time.time() zone = session.zone username = session.username object_name = 'foo_{ts}.txt'.format(**locals()) object_path = "/{zone}/home/{username}/{object_name}".format( **locals()) obj = helpers.make_object(session, object_path) # rule body rule_body = textwrap.dedent('''\ test {{ # add metadata *attribute.*name = *value; msiAssociateKeyValuePairsToObj(*attribute, *object, "-d") }}''') # rule parameters input_params = { # extra quotes for string literals '*object': '"{object_path}"'.format(**locals()), '*name': '"{attr_name}"'.format(**locals()), '*value': '"{attr_value}"'.format(**locals()) } output = 'ruleExecOut' # run test rule myrule = Rule(session, body=rule_body, irods_3_literal_style=True, params=input_params, output=output) myrule.execute() # check that metadata is there meta = session.metadata.get(DataObject, object_path) assert meta[0].name == attr_name assert meta[0].value == attr_value # remove test object obj.unlink(force=True)
def test_add_metadata_from_rule_file(self): ''' Tests running a rule from a client-side .r file. The rule adds metadata attributes to an iRODS object and we check for the presence of said attributes. ''' session = self.sess # test metadata attr_name = "test_attr" attr_value = "test_value" # make test object ts = time.time() zone = session.zone username = session.username object_name = 'foo_{ts}.txt'.format(**locals()) object_path = "/{zone}/home/{username}/{object_name}".format( **locals()) obj = helpers.make_object(session, object_path) # make rule file rule_file_path = "/tmp/test_{ts}.r".format(**locals()) rule = textwrap.dedent('''\ test {{ # add metadata *attribute.*name = *value; msiAssociateKeyValuePairsToObj(*attribute, *object, "-d") }} INPUT *object="{object_path}",*name="{attr_name}",*value="{attr_value}" OUTPUT ruleExecOut'''.format(**locals())) with open(rule_file_path, "w") as rule_file: rule_file.write(rule) # run test rule myrule = Rule(session, rule_file_path) myrule.execute() # check that metadata is there meta = session.metadata.get(DataObject, object_path) assert meta[0].name == attr_name assert meta[0].value == attr_value # remove test object obj.unlink(force=True) # remove rule file os.remove(rule_file_path)
def test_add_metadata_from_rule(self): ''' Runs a rule whose body and input parameters are created in our script. The rule adds metadata attributes to an iRODS object and we check for the presence of said attributes. ''' session = self.sess # test metadata attr_name = "test_attr" attr_value = "test_value" # make test object ts = time.time() zone = session.zone username = session.username object_name = 'foo_{ts}.txt'.format(**locals()) object_path = "/{zone}/home/{username}/{object_name}".format( **locals()) obj = helpers.make_object(session, object_path) # rule body rule_body = textwrap.dedent('''\ test {{ # add metadata *attribute.*name = *value; msiAssociateKeyValuePairsToObj(*attribute, *object, "-d") }}''') # rule parameters input_params = { # extra quotes for string literals '*object': '"{object_path}"'.format(**locals()), '*name': '"{attr_name}"'.format(**locals()), '*value': '"{attr_value}"'.format(**locals()) } output = 'ruleExecOut' # run test rule myrule = Rule(session, body=rule_body, params=input_params, output=output) myrule.execute() # check that metadata is there meta = session.metadata.get(DataObject, object_path) assert meta[0].name == attr_name assert meta[0].value == attr_value # remove test object obj.unlink(force=True)
def test_rules_query__267(self): unique = "Testing prc #267: queryable rule objects" with NamedTemporaryFile(mode='w') as rfile: rfile.write("""f() {{ delay('<EF>1m</EF>') {{ writeLine('serverLog','{unique}') }} }}\n""" """OUTPUT null\n""".format(**locals())) rfile.flush() ## create a delayed rule we can query against myrule = Rule(self.sess, rule_file = rfile.name) myrule.execute() qu = self.sess.query(RuleExec.id).filter( Like(RuleExec.frequency,'%1m%'), Like(RuleExec.name, '%{unique}%'.format(**locals())) ) results = [row for row in qu] self.assertEqual(1, len(results)) if results: Rule(self.sess).remove_by_id( results[0][RuleExec.id] )
def test_retrieve_std_streams_from_rule(self): ''' Tests running a rule from a client-side .r file. The rule writes things to its stdout that we get back on the client side ''' # Wrong buffer length on older versions if self.sess.server_version < (4, 1, 7): self.skipTest('For iRODS 4.1.7 and newer') session = self.sess # test metadata some_string = u'foo' some_other_string = u'我喜欢麦当劳' err_string = u'⛔' # make rule file ts = time.time() rule_file_path = "/tmp/test_{ts}.r".format(**locals()) rule = textwrap.dedent(u'''\ test {{ # write stuff writeLine("stdout", *some_string); writeLine("stdout", *some_other_string); writeLine("stderr", *err_string); }} INPUT *some_string="{some_string}",*some_other_string="{some_other_string}",*err_string="{err_string}" OUTPUT ruleExecOut'''.format(**locals())) with open(rule_file_path, "w") as rule_file: if six.PY2: rule_file.write(rule.encode('utf-8')) else: rule_file.write(rule) # run test rule myrule = Rule(session, rule_file_path) out_array = myrule.execute() # retrieve out buffer buf = out_array.MsParam_PI[0].inOutStruct.stdoutBuf.buf # it's binary data (BinBytesBuf) so must be decoded buf = buf.decode('utf-8') # check that we get our strings back self.assertIn(some_string, buf) self.assertIn(some_other_string, buf) # same thing stderr buffer buf = out_array.MsParam_PI[0].inOutStruct.stderrBuf.buf # decode and check buf = buf.decode('utf-8') self.assertIn(err_string, buf) # remove rule file os.remove(rule_file_path)
def _ruleExec(self, rule_file_path): self._irodsConnect() #print("path rule: "+rule_file_path) # run rule myrule = Rule(self.session, rule_file_path) ruleout = myrule.execute() return ruleout
def _with_X_instance_when_rule_multiply_defined(self, **kw): session = self.sess rule = Rule( session, body='defined_in_both', output='ruleExecOut', **{key: val for key, val in kw.items() if key == 'instance_name'}) output = rule.execute() buf = output.MsParam_PI[0].inOutStruct.stdoutBuf.buf self.assertTrue(kw['test_condition'](buf.rstrip(b'\0').rstrip()))
def get_server_ssl_negotiation(session): rule_body = textwrap.dedent(''' test { *out=""; acPreConnect(*out); writeLine("stdout", "*out"); } ''') myrule = Rule(session, body=rule_body, params={}, output='ruleExecOut') out_array = myrule.execute() buf = out_array.MsParam_PI[0].inOutStruct.stdoutBuf.buf.decode('utf-8') eol_offset = buf.find('\n') return buf[:eol_offset] if eol_offset >= 0 else None
def rule(self, name, body, inputs, output=False): import textwrap rule_body = textwrap.dedent('''\ %s {{ %s }}''' % (name, body)) outname = None if output: outname = 'ruleExecOut' myrule = Rule(self.prc, body=rule_body, params=inputs, output=outname) try: raw_out = myrule.execute() except BaseException as e: msg = 'Irule failed: %s' % e.__class__.__name__ log.error(msg) log.warning(e) # raise IrodsException(msg) raise e else: log.debug("Rule %s executed: %s", name, raw_out) # retrieve out buffer if output and len(raw_out.MsParam_PI) > 0: out_array = raw_out.MsParam_PI[0].inOutStruct # print("out array", out_array) import re file_coding = 'utf-8' buf = out_array.stdoutBuf.buf if buf is not None: # it's binary data (BinBytesBuf) so must be decoded buf = buf.decode(file_coding) buf = re.sub(r'\s+', '', buf) buf = re.sub(r'\\x00', '', buf) buf = buf.rstrip('\x00') log.debug("Out buff: %s", buf) err_buf = out_array.stderrBuf.buf if err_buf is not None: err_buf = err_buf.decode(file_coding) err_buf = re.sub(r'\s+', '', err_buf) log.debug("Err buff: %s", err_buf) return buf return raw_out """
def _failing_in_targeted_rule_engines(self, rule_to_call=None): session = self.sess if isinstance(rule_to_call, (list, tuple)): rule_dict = dict(rule_to_call) else: rule_dict = {} rule_instances_list = ( 'irods_rule_engine_plugin-irods_rule_language-instance', 'irods_rule_engine_plugin-python-instance') err_hash = {} for i in rule_instances_list: if rule_dict: rule_to_call = rule_dict[i] rule = Rule(session, body=rule_to_call, instance_name=i) try: rule.execute(acceptable_errors=(-1, )) except UnknowniRODSError as e: err_hash[i] = ('rule exec failed! - misc - ', (e) ) # 2-tuple = failure except RULE_ENGINE_ERROR as e: err_hash[i] = ('rule exec failed! - python - ', (e) ) # 2-tuple = failure except FAIL_ACTION_ENCOUNTERED_ERR as e: err_hash[i] = ('rule exec failed! - native - ', (e)) else: err_hash[i] = ('rule exec succeeded!', ) # 1-tuple = success self.assertEqual(len(err_hash), len(rule_instances_list)) self.assertEqual( len(err_hash), len([ val for val in err_hash.values() if val[0].startswith('rule exec failed') ])) return err_hash
def execute_rule(rule_body, input_params, rule_info): myrule = Rule(rule_info.session, body=rule_body, params=input_params, output="*result") result = myrule.execute() if rule_info.get_result: buf = result.MsParam_PI[0].inOutStruct.myStr buf_json = json.loads(buf) # Check if it will return the JSON rule's output or the DTO if rule_info.parse_to_dto: return rule_info.dto.create_from_rule_result(buf_json) else: return buf_json return
def execute_rule(self, rule_path, input_parameters): """ Executes a rule from given file path with input parameters """ rule = Rule(self.session, rule_path, params=input_parameters, output="ruleExecOut") output = rule.execute() # This is insane but the output of writeLine is here return output.MsParam_PI[0].inOutStruct.stdoutBuf.buf.decode( "utf-8").strip("\x00")
def rule_checksum(self, path): logger.info(f"{'--':<20}Rule checksum") self.session.connection_timeout = 1200 rule_body = "do_checkSum {" \ "{ msiDataObjChksum(" \ "'"+path+"'," \ "'forceChksum=', *chkSum);\n" \ "writeLine('stdout', *chkSum);}}" rule = Rule(self.session, body=rule_body, output="ruleExecOut") irods_hash = self.parse_rule_output(rule.execute()).split('sha2:')[1] base_hash = base64.b64decode(irods_hash) irods_hash_decode = binascii.hexlify(base_hash).decode("utf-8") self.session.connection_timeout = 120 return irods_hash_decode
def rule_collection_checksum(path): logger.info(f"{'--':<10}Query collection checksum") session = iRODSSession(host=os.environ['IRODS_HOST'], port=1247, user=os.environ['IRODS_USER'], password=os.environ['IRODS_PASS'], zone='nlmumc') session.connection_timeout = 1200 path = path.split('/') project = path[3] collID = path[4] rule_body = f"""do_checkSum(){{ *project = '{project}'; *collID = '{collID}'; *collection = '/nlmumc/projects/*project/*collID'; *details = "{{}}"; foreach ( *Row in SELECT DATA_PATH, COLL_NAME WHERE COLL_NAME like "*collection%") {{ *subName = triml(*Row.DATA_PATH,*collID); *name = *collection ++ str(*subName); msiDataObjChksum(*name,"forceChksum=", *chkSum); *chkSum = triml(*chkSum,"sha2:"); msiString2KeyValPair("", *titleKvp); msiAddKeyVal(*titleKvp, *name, *chkSum); msi_json_objops(*details, *titleKvp, "add"); }} writeLine('stdout', *details); }} """ rule = Rule(session, body=rule_body, output="ruleExecOut") irods_hash = RuleManager.parse_rule_output(rule.execute()) session.connection_timeout = 120 data = json.loads(irods_hash) for k in data: base_hash = base64.b64decode(data[k]) irods_hash_decode = binascii.hexlify(base_hash).decode("utf-8") data[k] = irods_hash_decode return data
def _ruleExec(self, rule_file_path): """Reads and runs a parameterless rule from a file. Parameters ---------- rule_file_path : `str` Path to rule file. """ self._irodsConnect() #print("path rule: "+rule_file_path) # run rule myrule = Rule(self.session, rule_file_path) ruleout = myrule.execute() return ruleout
def test_retrieve_std_streams_from_rule(self): ''' Tests running a rule from a client-side .r file. The rule writes things to its stdout that we get back on the client side ''' session = self.sess # test metadata some_string = "foo" some_other_string = "bar" err_string = "baz" # make rule file ts = time.time() rule_file_path = "/tmp/test_{ts}.r".format(**locals()) rule = textwrap.dedent('''\ test {{ # write stuff writeLine("stdout", *some_string); writeLine("stdout", *some_other_string); writeLine("stderr", *err_string); }} INPUT *some_string="{some_string}",*some_other_string="{some_other_string}",*err_string="{err_string}" OUTPUT ruleExecOut'''.format(**locals())) with open(rule_file_path, "w") as rule_file: rule_file.write(rule) # run test rule myrule = Rule(session, rule_file_path) out_array = myrule.execute() # check stdout outbuf = out_array.MsParam_PI[0].inOutStruct.stdoutBuf.buf self.assertIn(some_string, outbuf) self.assertIn(some_other_string, outbuf) # check stderr errbuf = out_array.MsParam_PI[0].inOutStruct.stderrBuf.buf self.assertIn(err_string, errbuf) # remove rule file os.remove(rule_file_path)
def test_rulefile_in_file_like_object_1__336(self): rule_file_contents = textwrap.dedent(u"""\ hw { helloWorld(*message); writeLine("stdout", "Message is: [*message] ..."); } helloWorld(*OUT) { *OUT = "Hello world!" } """) r = Rule(self.sess, rule_file=io.StringIO(rule_file_contents), output='ruleExecOut', instance_name= 'irods_rule_engine_plugin-irods_rule_language-instance') output = r.execute() lines = self.lines_from_stdout_buf(output) self.assertRegexpMatches(lines[0], '.*\[Hello world!\]')
def _with_writeline_to_stream(self, stream_name="serverLog", output_string='test-writeline-to-stream', alternate_input_params=(), rule_engine_instance=""): session = self.sess # rule body rule_body = textwrap.dedent('''\ writeLine("{stream_name}","*value") '''.format(**locals())) input_params = {'*value': output_string} input_params.update(alternate_input_params) output_param = 'ruleExecOut' extra_options = {} if rule_engine_instance: extra_options['instance_name'] = rule_engine_instance myrule = Rule(session, body=rule_body, params=input_params, output=output_param, **extra_options) output = myrule.execute() buf = None if stream_name == 'stdout': buf = output.MsParam_PI[0].inOutStruct.stdoutBuf.buf elif stream_name == 'stderr': buf = output.MsParam_PI[0].inOutStruct.stderrBuf.buf if buf is not None: buf = buf.decode('utf-8') self.assertEqual(output_string, buf.rstrip('\0').rstrip())
def rule_deletion(self, upload_success): logger.info("Rule deletion") # Check if all the files have been successfully uploaded before deletion if len(upload_success) == len(self.collection.data_objects): logger.info(f"{'--':<20}Start deletion") for data in self.collection.data_objects: if data.name != "metadata.xml": rule_body = "do_deleteDataObject {" \ "{ msiDataObjUnlink(" \ "'/nlmumc/projects/"+self.projectID+"/"+self.collectionID+"/"+data.name+"'," \ "'forceChksum=', *chkSum);\n" \ "writeLine('stdout', *chkSum);}}" rule = Rule(self.session, body=rule_body, output="ruleExecOut") out = self.parse_rule_output(rule.execute()) if out == "0": logger.info(f"{'--':<30} Delete:\t" + data.name) else: logger.error(f"{'--':<30} File:\t" + out) logger.info(f"{'--':<30} End deletion") else: logger.info("Deletion skipped. collection.files != uploaded.files")
def flush(self, irods_object_list, buff): rule_code = ("getDmf {\n" + " *lst=" + irods_object_list + ";\n" + " *res=\"\";\n" + " " + self.msi_name + "(*lst, *res);\n" + "}\n") myrule = Rule(self.irods.session, body=rule_code, output="*res") try: res = myrule.execute() except Exception as e: self.logger.error(str(e)) for line in rule_code.split('\n'): self.logger.error(line) self.logger.error('*lst: "{0}"'.format(irods_object_list)) raise dmf_values = {obj['objPath']: obj for obj in json.loads(self.get_rule_return_value(res, 0))} for p in buff.keys(): if p[0] in dmf_values: buff[p].update(self.transform(dmf_values[p[0]])) return buff.values()
def rule_collection_checksum(path): logger.info(f"{'--':<10}Query collection checksum") ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None) ssl_settings = { "irods_client_server_negotiation": "request_server_negotiation", "irods_client_server_policy": os.environ["IRODS_CLIENT_SERVER_POLICY"], "irods_encryption_algorithm": "AES-256-CBC", "irods_encryption_key_size": 32, "irods_encryption_num_hash_rounds": 16, "irods_encryption_salt_size": 8, "ssl_context": ssl_context, } session = iRODSSession( host=os.environ["IRODS_HOST"], port=1247, user=os.environ["IRODS_USER"], password=os.environ["IRODS_PASS"], zone="nlmumc", **ssl_settings, ) session.connection_timeout = 1200 path = path.split("/") project = path[3] collID = path[4] rule_body = f"""do_checkSum(){{ *project = '{project}'; *collID = '{collID}'; *collection = '/nlmumc/projects/*project/*collID'; *details = "{{}}"; foreach ( *Row in SELECT DATA_PATH, COLL_NAME WHERE COLL_NAME like "*collection%") {{ *subName = triml(*Row.DATA_PATH,*collID); *name = *collection ++ str(*subName); msiDataObjChksum(*name,"forceChksum=", *chkSum); *chkSum = triml(*chkSum,"sha2:"); msiString2KeyValPair("", *titleKvp); msiAddKeyVal(*titleKvp, *name, *chkSum); msi_json_objops(*details, *titleKvp, "add"); }} writeLine('stdout', *details); }} """ rule = Rule(session, body=rule_body, output="ruleExecOut") irods_hash = RuleManager.parse_rule_output(rule.execute()) session.connection_timeout = 120 session.cleanup() data = json.loads(irods_hash) for k in data: base_hash = base64.b64decode(data[k]) irods_hash_decode = binascii.hexlify(base_hash).decode("utf-8") data[k] = irods_hash_decode return data
def main(): module = AnsibleModule(argument_spec=dict(groupName=dict(default=None, required=True), category=dict(default=None, required=True), subcategory=dict(default=None, required=True), description=dict(default=None, required=True), dataClassification=dict( default=None, required=True), state=dict(default="present")), supports_check_mode=True) groupName = module.params["groupName"] category = module.params["category"] subcategory = module.params["subcategory"] description = module.params["description"] dataClassification = module.params["dataClassification"] state = module.params["state"] if IRODSCLIENT_AVAILABLE: try: session, ienv = get_session() except iRODSException: module.fail_json( msg= "Could not establish irods connection. Please check ~/.irods/irods_environment.json" ) else: module.fail_json(msg="python-irodsclient needs to be installed") changed = False # Rule to add a group to Yoda. rule_body = textwrap.dedent('''\ test {{ uuGroupAdd(*groupName, *category, *subcategory, *description, *dataClassification, *status, *message); }}''') # Rule parameters. input_params = { '*groupName': '"{groupName}"'.format(**locals()), '*category': '"{category}"'.format(**locals()), '*subcategory': '"{subcategory}"'.format(**locals()), '*description': '"{description}"'.format(**locals()), '*dataClassification': '"{dataClassification}"'.format(**locals()) } output = 'ruleExecOut' # Execute rule. if not module.check_mode: myrule = Rule(session, body=rule_body, params=input_params, output=output) myrule.execute() changed = True module.exit_json(changed=changed, irods_environment=ienv)