def __init__(self, emperor): emperor = Emperor() ''' host : istance of class Host ''' self.host = emperor.host self.name = emperor.name if 'pid' in emperor.directory: self.pidDir = emperor.directory['pid'] else: self.pidDir = '/tmp/uwsgi/run' if 'log' in emperor.directory: self.logDir = emperor.directory['log'] else: self.logDir = '/tmp/uwsgi/log' if 'vassal' in emperor.directory: self.vassalSearchPath = emperor.directory['vassal'] else: self.vassalSearchPath = '/tmp/uwsgi/vassals/' self.uwsgiPath = '' self.uwsgiExec = 'uwsgi' #self.db_conn_string = '' self.statsPort = 1717 if 'stats' in emperor.ports: self.statsPort = int(emperor.ports['stats']) else: self.statsPort = 1717 self.remoteClient = RemoteClient(self.host.name) self.remoteManager = RemoteManager(self.host) self.check = None
def run_ssh_command(self, oid, user, pwd, cmd): server = self.entity_class.get(oid) ip = server[u'addresses'].values()[0][0][u'addr'] client = RemoteClient({u'host': ip, u'port': 22}) res = client.run_ssh_command(cmd, user, pwd) if res.get(u'stderr' != u''): print(u'Error') print(res.get(u'stderr')) else: for row in res.get(u'stdout'): print(row)
def run_ssh_command(self, oid, user, pwd, cmd): server = self.entity_class.get_by_morid(oid) data = self.entity_class.data(server) client = RemoteClient({u'host':data[u'networks'][0][u'fixed_ips'], u'port':22}) res = client.run_ssh_command(cmd, user, pwd) if res.get(u'stderr' != u''): print(u'Error') print(res.get(u'stderr')) else: for row in res.get(u'stdout'): print(row)
def setUp(self): logging.getLogger(u'beehive.test')\ .info(u'========== %s ==========' % self.id()[9:]) self.start = time.time() # ssl path = os.path.dirname(__file__).replace(u'beehive/common', u'beehive/tests') pos = path.find(u'tests') path = path[:pos + 6] #keyfile = u'%s/ssl/nginx.key' % path #certfile = u'%s/ssl/nginx.key' % path keyfile = None certfile = None # load config config = self.load_config(u'%s/params.json' % path) #for k,v in self.load_config(): # setattr(self, k, v) env = config.get(u'env') current_user = config.get(u'user') current_schema = config.get(u'schema') cfg = config.get(env) # endpoints self.endpoints = cfg.get(u'endpoints') # redis connection self.redis_uri = cfg.get(u'redis-uri') rhost, rport, db = self.redis_uri.split(u';') self.redis = redis.StrictRedis(host=rhost, port=int(rport), db=int(db)) # celery broker self.broker = cfg.get(u'broker') # mysql connection self.db_uri = cfg.get(u'db-uris').get(current_schema) # get users self.users = cfg.get(u'users') self.user = self.users.get(current_user).get(u'user') self.pwd = self.users.get(current_user).get(u'pwd') self.ip = self.users.get(current_user).get(u'ip') # create auth client self.auth_client = BeehiveApiClient([], u'keyauth', None, None) # create api endpoint self.api = {} for subsystem, endpoint in self.endpoints.items(): self.api[subsystem] = RemoteClient(endpoint, keyfile=keyfile, certfile=certfile)
def __init__(self, conn, user='******', passwd='anonymous', proxy=None, keyfile=None, certfile=None): """ :param conn: Request connection. Ex. {'host':'10.102.160.12', 'port':9090, 'path':'/engine-rest', 'proto':'http'} :param proxy: proxy server. Ex. ('proxy.it', 3128) [default=None] http:/10.102.160.12:9090/engine-rest/ """ #self.logger = getLogger('behive_bpm') self.logger = getLogger(self.__class__.__module__+ \ '.'+self.__class__.__name__) self.baseurl = "" self.connection = conn self.user = user self.password = passwd self.proxy = proxy self.client = RemoteClient(conn, user, passwd, proxy) self.baseheader = { 'Authorization': 'Basic ' + base64.b64encode(user + ':' + passwd) }
def run_ssh_command(self, cmd): try: remote = RemoteClient(self.host) return remote.run_ssh_command(cmd, self.user, self.pwd, 22) except RemoteException as e: raise VirtManagerError(e)
class EmperorManager(object): ''' Class used to manage remote emperor instance. start : uwsgi --ini emperor.ini stop : uwsgi --stop run/emperor.pid reload : uwsgi --reload run/emperor.pid ''' def __init__(self, emperor): emperor = Emperor() ''' host : istance of class Host ''' self.host = emperor.host self.name = emperor.name if 'pid' in emperor.directory: self.pidDir = emperor.directory['pid'] else: self.pidDir = '/tmp/uwsgi/run' if 'log' in emperor.directory: self.logDir = emperor.directory['log'] else: self.logDir = '/tmp/uwsgi/log' if 'vassal' in emperor.directory: self.vassalSearchPath = emperor.directory['vassal'] else: self.vassalSearchPath = '/tmp/uwsgi/vassals/' self.uwsgiPath = '' self.uwsgiExec = 'uwsgi' #self.db_conn_string = '' self.statsPort = 1717 if 'stats' in emperor.ports: self.statsPort = int(emperor.ports['stats']) else: self.statsPort = 1717 self.remoteClient = RemoteClient(self.host.name) self.remoteManager = RemoteManager(self.host) self.check = None ''' def set_db_conn_string(self, db_conn_string): self.db_conn_string = db_conn_string ''' def check_environment(self): ''' Check if directories exists over remote portal2 and create them if they don't exists ''' try: self.check = {} # check distribution self.check['distro'] = self.remoteManager.detect_distribution() # check python self.check['python'] = self.remoteManager.detect_python() # check gcc self.check['gcc'] = self.remoteManager.detect_gcc() # check uwsgi self.check['uwsgi'] = self.remoteManager.detect_uwsgi() # check if self.pidDir exists self.check['pid_dir'] = self.remoteManager.create_directory( self.pidDir) # check if self.logDir exists self.check['log_dir'] = self.remoteManager.create_directory( self.logDir) # check if self.vassalSearchPath exists self.check[ 'vassalSearchPath'] = self.remoteManager.create_directory( self.vassalSearchPath) return self.check except RemoteExcpetion as ex: raise EmperorManagerExcpetion('Error running check environment: ' + str(ex)) def start(self): ''' Start emperor istance on a remote portal2 uwsgi --ini emperor.ini #socket = :3031 plugin = emperor_pg emperor = pg://host=127.0.0.1 user=gibbon password=gibbon dbname=gibbon;SELECT name,config,ts FROM emperor_vassals # enable the master process master = true #processes = 4 #enable-threads #threads = 40 procname = emperor daemonize = log/uwsgi-emperor.log pidfile = run/emperor.pid log-master vacuum = true #stats = 1717 ''' if self.check == None: self.check_environment() if self.check['uwsgi'] == None: raise EmperorManagerExcpetion('uwsgi is not installed') try: params = [ #'--plugin', 'emperor_pg', #'--emperor', '"'+self.db_conn_string+'"', '--emperor', '"' + self.vassalSearchPath + '*.ini"', '--master', '--procname', self.name, '--daemonize', self.logDir + '/' + self.name + '.log', '--pidfile', self.pidDir + '/' + self.name + '.pid', '--log-master', '', '--vacuum', '--stats', ":%s" % self.statsPort, ] cmd = 'cd %s && %s %s' % (self.uwsgiPath, self.uwsgiExec, ' '.join(params)) res = self.remoteClient.run_ssh_command(cmd, self.host.ssh2['user'], self.host.ssh2['pwd']) if len(res['stderr']) > 0: raise RemoteExcpetion(res['stderr']) else: return True except RemoteExcpetion as ex: raise EmperorManagerExcpetion( 'Error starting new emperor istance: ' + str(ex)) def stop(self): ''' Stop emperor istance on a remote portal2 uwsgi --stop run/emperor.pid ''' if self.check == None: self.check_environment() if self.check['uwsgi'] == None: raise EmperorManagerExcpetion('uwsgi is not installed') try: cmd = 'cd %s && %s --stop %s/%s.pid' % ( self.uwsgiPath, self.uwsgiExec, self.pidDir, self.name) res = self.remoteClient.run_ssh_command(cmd, self.host.ssh2['user'], self.host.ssh2['pwd']) if len(res['stderr']) > 0: raise RemoteExcpetion(res['stderr']) else: return True except RemoteExcpetion as ex: raise EmperorManagerExcpetion( 'Error stopping new emperor istance: ' + str(ex)) def reload(self): ''' Reload emperor istance on a remote portal2 uwsgi --reload run/emperor.pid ''' if self.check == None: self.check_environment() if self.check['uwsgi'] == None: raise EmperorManagerExcpetion('uwsgi is not installed') try: cmd = 'cd %s && %s --reload %s/%s.pid' % ( self.uwsgiPath, self.uwsgiExec, self.pidDir, self.name) res = self.remoteClient.run_ssh_command(cmd, self.host.ssh2['user'], self.host.ssh2['pwd']) if len(res['stderr']) > 0: raise RemoteExcpetion(res['stderr']) else: return True except RemoteExcpetion as ex: raise EmperorManagerExcpetion( 'Error reloading new emperor istance: ' + str(ex))
def setUpClass(cls): logger.log( 60, '#################### Testplan %s - START ####################' % cls.__name__) logging.getLogger('beehive.test.run')\ .log(60, '#################### Testplan %s - START ####################' % cls.__name__) self = cls # ssl path = os.path.dirname(__file__).replace('beehive/common', 'beehive/tests') pos = path.find('tests') path = path[:pos + 6] keyfile = None certfile = None # load configs try: home = os.path.expanduser('~') if self.main_config_file is None: config_file = '%s/beehive.yml' % home self.main_config_file = config_file else: config_file = self.main_config_file config = self.load_file(config_file) logger.info('Get beehive test configuration: %s' % config_file) except Exception as ex: raise Exception( 'Error loading config file. Search in user home. %s' % ex) # load configs fernet key try: home = os.path.expanduser('~') if self.main_config_file is None: config_file = '%s/beehive.fernet' % home self.main_fernet_file = config_file else: config_file = self.main_config_file.replace('yml', 'fernet') fernet = self.load_file(config_file) logger.info('Get beehive test fernet key: %s' % config_file) except Exception as ex: raise Exception( 'Error loading fernet key file. Search in user home. %s' % ex) # load specific configs for a set of test try: if self.spec_config_file is not None: config2 = self.load_file(self.spec_config_file) recursive_update(config, config2) logger.info('Get beehive test specific configuration: %s' % self.spec_config_file) except Exception as ex: raise Exception( 'Error loading config file. Search in user home. %s' % ex) logger.info('Validation active: %s' % cls.validation_active) cfg = config self.test_config = config.get('configs', {}) if self.test_config.get('resource', None) is not None: for key in self.test_config.get('resource').keys(): if 'configs' in cfg.keys() and 'resource' in cfg.get( 'configs').keys(): self.test_config.get('resource').get(key).update( cfg.get('configs').get('resource').get(key, {})) if 'configs' in cfg.keys() and 'container' in cfg.get( 'configs').keys(): self.test_config.get('container').update( cfg.get('configs').get('container')) self.fernet = fernet # endpoints self.endpoints = cfg.get('endpoints') self.swagger_endpoints = cfg.get('swagger') logger.info('Endpoints: %s' % self.endpoints) # redis connection if cfg.get('redis') is not None: self.redis_uri = cfg.get('redis').get('uri') if self.redis_uri is not None and self.redis_uri != '': rhost, rport, db = self.redis_uri.split(';') self.redis = redis.StrictRedis(host=rhost, port=int(rport), db=int(db)) # celery broker self.worker = cfg.get('worker') # mysql connection self.db_uris = cfg.get('db-uris') # get users self.users = cfg.get('users') # create auth client self.auth_client = BeehiveApiClient([], 'keyauth', None, '', None) # create api endpoint self.api = {} self.schema = {} for subsystem, endpoint in self.endpoints.items(): self.api[subsystem] = RemoteClient(endpoint, keyfile=keyfile, certfile=certfile) self.load_result() self.custom_headers = {} self.endpoit_service = 'auth'
class WorkFlowEngine(object): """ WorkFlowEngine a wrapper around Camunnda bpmn engine """ # external task query parameters ext_task_queryitem = ('externalTaskId', 'topicName', 'workerId', 'locked', 'notLocked', 'withRetriesLeft', 'noRetriesLeft', 'activityId', 'executionId', 'processInstanceId', 'processDefinitionId', 'active', 'priorityHigherThanOrEquals', 'priorityLowerThanOrEquals', 'suspended', 'sortBy', 'sortOrder', 'firstResult', 'maxResults') def __init__(self, conn, user='******', passwd='anonymous', proxy=None, keyfile=None, certfile=None): """ :param conn: Request connection. Ex. {'host':'10.102.160.12', 'port':9090, 'path':'/engine-rest', 'proto':'http'} :param proxy: proxy server. Ex. ('proxy.it', 3128) [default=None] http:/10.102.160.12:9090/engine-rest/ """ #self.logger = getLogger('behive_bpm') self.logger = getLogger(self.__class__.__module__+ \ '.'+self.__class__.__name__) self.baseurl = "" self.connection = conn self.user = user self.password = passwd self.proxy = proxy self.client = RemoteClient(conn, user, passwd, proxy) self.baseheader = { 'Authorization': 'Basic ' + base64.b64encode(user + ':' + passwd) } # list of class that define a service #self.service_classes = service_classes #self.service_classes.insert(0, Service) def process_deployment_create( self, source, name, checkduplicate=True, changeonly=True, tenantid=None): '''Create a deployment and the process definition inside it :param name: STRING The name for the deployment to be created. :param checkduplicate: BOOLEAN :param changeonly: :param source: text/plain :param tenantid: str POST /deployment/create ''' import requests if checkduplicate: edf = 'true' else: edf = 'false' payload = [ ('deployment-name', name), ('enable-duplicate-filtering', edf), ('deployment-source', 'beehive process application'), ('data', (name + '.bpmn', source)) ] path = self.connection["proto"] + "://" + str(self.connection["host"]) + ":" + \ str(self.connection["port"]) + \ self.connection["path"] + '/deployment/create' r = requests.post(path, auth=(self.user, self.password), files=payload) r.raise_for_status() return r def process_deployment_delete( self, processDeploymentId, cascade=True, skipCustomListeners=False ): '''Delete a deployment :param cascade: BOOLEAN, true, if all process instances, historic process instances and jobs for this deployment should be deleted. :param skipCustomListeners: BOOLEAN true, if only the built-in ExecutionListeners should be notified with the end event. DELETE /deployment/{id} ''' query = {} query['cascade'] = cascade query['skipCustomListeners'] = skipCustomListeners path = '/deployment/%s'%processDeploymentId path = '%s?%s' % (path, urlencode(query)) if cascade == True: processes = self.process_definition_get(deploymentId=processDeploymentId) #self.logger.info('Processes to be deleted ' + str(process_definition_list)) for process in processes: self.logger.info('Processes to be deleted type' + str(type(processes))) processDefinitionId = process['id'] self.process_definition_delete(processDefinitionId=processDefinitionId, cascade=True, skipCustomListeners=True) #return processDefinitionId return self.client.run_http_request2(path, 'DELETE') # import requests # path = self.connection["proto"] + "://" + str(self.connection["host"]) + ":" + \ # str(self.connection["port"]) + \ # self.connection["path"] + '/deployment/%s'%processDeploymentId # path = '%s?%s' % (path, urlencode(query)) # r = requests.delete(path, auth=(self.user, self.password)) # r.raise_for_status() # return r.json() def process_deployment_get(self,processDeploymentId=None): '''Create a deployment :param id: STRING depployment identifier GET /deployment/{id} ''' if processDeploymentId == None: processDeploymentId='' path = self.baseurl + '/deployment/%s' %processDeploymentId return self.client.run_http_request2(path, 'GET') # import requests # path = self.connection["proto"] + "://" + str(self.connection["host"]) + ":" + \ # str(self.connection["port"]) + \ # self.connection["path"] + '/deployment/%s'%processDeploymentId # r = requests.get(path, auth=(self.user, self.password)) # r.raise_for_status() # return r.json() def case_definition_get(self,processDeploymentId=None): '''Queries for case definitions that fulfill given parameters :param processDeploymentId: STRING depployment identifier GET /case-definition ''' query={} query['deploymentId'] = processDeploymentId path = '/case-definition' path = '%s?%s' % (path, urlencode(query)) return self.client.run_http_request2(path, 'GET') def process_definition_xml_get(self, processDefinitionId=None, key=None, tenantId=None): '''Retrieves the BPMN 2.0 XML of a process definition. :param processDefinitionId STRING: process identifier :param key STRING: key the key identifier for the process we use the process key in order to always use last revision of the project :param tenantId STRING: the tenant identifier Get XML GET /process-definition/{id}/xml GET /process-definition/key/{key}/xml GET /process-definition/key/{key}/tenant-id/{tenant-id}/xml ''' if processDefinitionId == None: if key != None: if tenantId == None: path = self.baseurl + '/process-definition/key/%s/xml' %key else: path = self.baseurl + '/process-definition/key/%s/tenant-id/%s/xml'%(key,tenantId) else: path = self.baseurl + '/process-definition/%s/xml' %processDefinitionId return self.client.run_http_request2(path, 'GET')['bpmn20Xml'] def process_definition_list(self): ''' Get the list of process definitions available Get List GET /process-definition ''' path = self.baseurl + '/process-definition' return self.client.run_http_request2(path, 'GET') def process_definition_get(self, processDefinitionId=None, key=None, tenantId=None, deploymentId=None): '''Get a process definition filtering on params :param processDefinitionId STRING: process identifier :param key STRING: key the key identifier for the process we use the process key in order to always use last revision of the project :param tenantId STRING: the tenant identifier :param deploymentId STRING: the deployment id GET /process-definition/{id} GET /process-definition/key/{key} (returns the latest version of the process definition which belongs to no tenant) GET /process-definition/key/{key}/tenant-id/{tenant-id} (returns the latest version of the process definition for tenant) ''' if processDefinitionId == None: if key != None: if tenantId == None: path = self.baseurl + '/process-definition/key/' + key else: path = self.baseurl + '/process-definition/key/%s/tenant-id/%s'%(key,tenantId) elif deploymentId != None: path = self.baseurl + '/process-definition?deploymentId=%s'%deploymentId else: path = self.baseurl + '/process-definition' else: path = self.baseurl + '/process-definition/%s'%processDefinitionId return self.client.run_http_request2(path, 'GET') def process_definition_delete( self, processDefinitionId, cascade=True, skipCustomListeners=True ): '''Delete a Process definition DELETE /process-definition/{id} :param cascade: BOOLEAN, true, if all process instances, historic process instances and jobs for this deployment should be deleted. :param skipCustomListeners: BOOLEAN true, if only the built-in ExecutionListeners should be notified with the end event. ''' import requests query = {} query['cascade'] = cascade query['skipCustomListeners'] = skipCustomListeners path = self.connection["proto"] + "://" + str(self.connection["host"]) + ":" + \ str(self.connection["port"]) + \ self.connection["path"] + '/process-definition/%s'%processDefinitionId path = '%s?%s' % (path, urlencode(query)) r = requests.delete(path, auth=(self.user, self.password)) r.raise_for_status() return r def process_instance_start_processDefinitionId(self, processDefinitionId, businessKey=None, variables=None): """ """ return self.process_instance_start_processkey(processDefinitionId, businessKey=businessKey, variables=variables) def process_instance_start_processkey(self, key, businessKey=None, variables=None): '''Instantiates a given process definition. Process variables and business key may be supplied. :param processDefinitionId: the id of the process definition :param businessKey: the value for businessKey The business key the process instance is to be initialized with. The business key uniquely identifies the process instance in the context of the given process definition :param process_variables: a dict with the process variables ''' if variables is None: variables = {} payload = self.variablesfrompyton(variables) if businessKey is not None: payload['businessKey'] = businessKey data = json.dumps(payload) return self.client.run_http_request2( '/process-definition/key/' + key + '/start', 'POST', data=data, headers={'Content-Type': 'application/json'}) def process_instances_list(self, processDefinitionKey=None, businessKey=None, processInstanceIds=None): """Get running process instances POST /process-instance Authorization: Basic YWRtaW46YWRtaW5hZG1pbg== :param processInstanceIds: LIST or STRING, a list of process instance or a single instance. :param businessKey: STRING process instance business key. :param processDefinitionKey: STRING Filter by the key of the process definition the instances run on attention: the key not the id. """ att_filter = {} if processDefinitionKey is not None: att_filter['processDefinitionKey'] = processDefinitionKey if businessKey is not None: att_filter['businessKey'] = businessKey if processInstanceIds is not None: if isinstance(processInstanceIds, list): att_filter['processInstanceIds'] = processInstanceIds else: att_filter['processInstanceIds'] = (processInstanceIds,) if len(att_filter) == 0: return None data = json.encode(att_filter) return self.client.run_http_request2( '/process-instance', 'POST', data=data, headers={'Content-Type': 'application/json'}) def process_instances_get_all(self): """ GET http://10.102.160.12:9090/engine-rest/process-instance HTTP/1.1 Authorization: Basic YWRtaW46YWRtaW5hZG1pbg== """ return self.client.run_http_request2('/process-instance', 'GET') def process_instance_history_detail(self, processInstanceId=None): """Get completed process instances GET /history/process-instance/{pprocessInstanceIds} Authorization: Basic YWRtaW46YWRtaW5hZG1pbg== :param processInstanceIds: LIST or STRING, a list of process instance or a single instance. """ path = "/history/process-instance/%s"%processInstanceId return self.client.run_http_request2( path, 'GET') def process_instance_status(self, processInstanceId=None): """Get completed process instances GET /history/process-instance/{pprocessInstanceIds} Authorization: Basic YWRtaW46YWRtaW5hZG1pbg== :param processInstanceIds: LIST or STRING, a list of process instance or a single instance. """ path = "/history/process-instance/%s"%processInstanceId return self.client.run_http_request2( path, 'GET')['state'] def process_instances_group_delete(self,processInstanceIds, deleteReason): """Deletes multiple process instances asynchronously (batch). POST /process-instance/delete Authorization: Basic YWRtaW46YWRtaW5hZG1pbg== :param processInstanceIds: a list of process instance. :param deleteReason: STRING the delete reason. NOTE: Shoould be available in last Camunda version """ import requests dicttoDelete = {} if deleteReason is not None: dicttoDelete['deleteReason'] = deleteReason if processInstanceIds is not None: if isinstance(processInstanceIds, list): dicttoDelete['processInstanceIds'] = processInstanceIds else: dicttoDelete['processInstanceIds'] = (processInstanceIds,) if len(dicttoDelete) == 0: return None data = json.dumps(dicttoDelete) res = self.client.run_http_request2( '/process-instance/delete', 'POST', data=data, headers={'Content-Type': 'application/json'}) return res def process_instance_delete(self, processInstanceId): """Deletes single process instances synchronously. DELETE /process-instance/{processInstanceId} :param processInstanceId: STRING the proces instance id """ try: path = self.baseurl + '/process-instance/' + \ processInstanceId result = self.client.run_http_request2(path, 'DELETE') except Exception as ex: return False return True def process_instance_variables_list(self, processInstanceId): """ Get List GET /process-instance/{id}/variables :param processInstanceId: the proces instance id """ path = self.baseurl + '/process-instance/' + processInstanceId + '/variables' result = self.client.run_http_request2(path, 'GET') return self.variablestopyton({'variables': result}) # Post (Binary) # POST /process-instance/{id}/variables/{varName}/data def process_instance_variables_list_ex(self, processInstanceId): """ gets all variables for a runing process """ pvar = self.client.run_http_request2( '/execution/' + processInstanceId + '/localVariables', 'GET') if pvar is None: pvar = {} return self.variablestopyton({'variables': pvar}) def process_instance_variable_get(self, processInstanceId, varName): """ Get GET /process-instance/{id}/variables/{varName} :param processInstanceId: the proces instance id :param varName: the name of the avariable to get """ path = self.baseurl + '/process-instance/' + \ processInstanceId + '/variables/' + varName result = self.client.run_http_request2(path, 'GET') return result # self.variablestopyton({'variables':result}) def process_instance_variable_file_upload(self, processInstanceId, varName, varContent): """Use only with files, with variables and dictionaries use update method Get (Binary) POST /process-instance/{id}/variables/{varName}/data contente is a string :param processInstanceId: the proces instance id :param varName: the name of the avariable to fill :param content: a file handler opened in binary mode "rb" or a string with the content (1) Post binary content of a byte array variable: POST /process-instance/aProcessInstanceId/variables/aVarName/data Request Body: ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y Content-Disposition: form-data; name="data"; filename="unspecified" Content-Type: application/octet-stream Content-Transfer-Encoding: binary <<Byte Stream ommitted>> ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y Content-Disposition: form-data; name="valueType" Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit Bytes ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y-- (2) Post the JSON serialization of a Java Class (deprecated): POST /process-instance/aProcessInstanceId/variables/aVarName/data Request Body: ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y Content-Disposition: form-data; name="data" Content-Type: application/json; charset=US-ASCII Content-Transfer-Encoding: 8bit ["foo", "bar"] ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y Content-Disposition: form-data; name="type" Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit java.util.ArrayList<java.lang.Object> ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y-- (3) Post a text file: POST /process-instance/aProcessInstanceId/variables/aVarName/data Request Body: ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y Content-Disposition: form-data; name="data"; filename="myFile.txt" Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: binary <<Byte Stream ommitted>> ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y Content-Disposition: form-data; name="valueType" Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit File ---OSQH1f8lzs83iXFHphqfIuitaQfNKFY74Y-- """ import requests payload = [ ('data', (varName, varContent, 'application/octet-stream')), ("valueType", ('Bytes', 'text/plain; charset=US-ASCII')) ] path = self.connection["proto"] + "://" + str(self.connection["host"]) + ":" + \ str(self.connection["port"]) + \ self.connection["path"] + '/process-instance/' + \ processInstanceId + '/variables/' + varName + '/data' r = requests.post(path, auth=(self.user, self.password), files=payload) return r.text '''def process_instance_variables_update_old(self, processInstanceId, variables=None, deletenames=None): """ Modify POST /process-instance/{id}/variables :param variables: a dictionary containig the variables :param deletenames: an iterable containg the delete variable names """ path = self.baseurl + '/process-instance/' + processInstanceId + '/variables' data = {} if isinstance(variables, dict): cvars = self.variablesfrompyton(variables) data['modifications'] = cvars['variables'] if hasattr(deletenames, '__iter__'): data['deletions'] = [x for x in deletenames] result = self.client.run_http_request2( path, 'POST', data=data, headers={'Content-Type': 'application/json'}) return result''' def process_instance_variables_update(self, processInstanceId, variables=None, deletenames=None): """ Modify POST /process-instance/{id}/variables :param variables: a dictionary containig the variables :param deletenames: an iterable containg the delete variable names """ path = self.baseurl + '/process-instance/' + processInstanceId + '/variables' data = {} if variables is None: variables = {} payload = self.variablesfrompyton(variables) if isinstance(variables, dict): cvars = self.variablesfrompyton(variables) data['modifications'] = cvars['variables'] if hasattr(deletenames, '__iter__'): data['deletions'] = [x for x in deletenames] data = json.encode(data) result = self.client.run_http_request2( path, 'POST', data=data, headers={'Content-Type': 'application/json'}) return result def process_instance_variable_set(self, processInstanceId, varName, varValue, varType=None, valueInfo={}): """Update a single variable to a value Update PUT /process-instance/{id}/variables/{varName} BODY: { "value" : "ab", "type" : "Object", "valueInfo" : { "objectTypeName": "com.example.MyObject", "serializationDataFormat": "application/xml" } } """ data = {"value" : varValue, "type": varType, "valueInfo":valueInfo} path = self.baseurl + '/process-instance/' + \ processInstanceId + '/variables/' + varName data = json.encode(data) result = self.client.run_http_request2( path, 'PUT', data=data, headers={'Content-Type': 'application/json'}) return result def process_instance_varariable_delete(self, processInstanceId, varName): """ Delete DELETE /process-instance/{id}/variables/{varName} :param processInstanceId: the proces instance id :param varName: the name of the avariable to delete """ try: path = self.baseurl + '/process-instance/' + \ processInstanceId + '/variables/' + varName result = self.client.run_http_request2(path, 'DELETE') except Exception as ex: return False return True def tasks_list(self, att_filter=None): '''Quuery tasks :param att_filter a dicrtionary containing the key-value to search {"id":"anId", "name":"aName", "assignee":"anAssignee", "created":"2013-01-23T13:42:42", "due":"2013-01-23T13:49:42", "followUp:":"2013-01-23T13:44:42", "delegationState":"RESOLVED", "description":"aDescription", "executionId":"anExecution", "owner":"anOwner", "parentTaskId":"aParentId", "priority":42, "processDefinitionId":"aProcDefId", "processInstanceId":"aProcInstId", "caseDefinitionId":"aCaseDefId", "caseInstanceId":"aCaseInstId", "caseExecutionId":"aCaseExecution", "taskDefinitionKey":"aTaskDefinitionKey", "formKey":"aFormKey", "tenantId":"aTenantId"} ''' if att_filter is None: att_filter = {} # head = {'Content-Type': 'application/json'} data = json.encode(att_filter) return self.client.run_http_request2( '/task', 'POST', data=data, headers={'Content-Type': 'application/json'}) def task_get(self, taskId=None): '''Query task GET /task/{id} :param taskId The id of the task to be retrieved. ''' path = "/task/%s"%taskId return self.client.run_http_request2( path, 'GET') def task_variables_get(self, taskId=None): ''' get task variablee tasks :param filter a dicrtionary cintaining the key value paure tio search ''' path = '/task/' + taskId + '/variables' ret = self.client.run_http_request2(path, 'GET') return ret def task_complete(self, taskid, variables=None): ''' :param processDefinitionId: the id aof the process :param process_variables: a dict with the process variables ''' if variables is None: variables = {} variables = self.variablesfrompyton(variables) # head = {'Content-Type': 'application/json'} data = json.encode(variables) return self.client.run_http_request2( '/task/' + taskid + '/complete', 'POST', data=data, headers={'Content-Type': 'application/json'}) ''' Get Rendered Start Form GET /process-definition/{id}/rendered-form GET /process-definition/key/{key}/rendered-form GET /process-definition/key/{key}/tenant-id/{tenant-id}/rendered-form Get Start Form Key GET /process-definition/{id}/startForm GET /process-definition/key/{key}/startForm GET /process-definition/key/{key}/tenant-id/{tenant-id}/startForm Get Process Instance Statistics GET /process-definition/statistics Submit Start Form POST /process-definition/{id}/submit-form POST /process-definition/key/{key}/submit-form POST /process-definition/key/{key}/tenant-id/{tenant-id}/submit-form Activate/Suspend By Id PUT /process-definition/{id}/suspended PUT /process-definition/key/{key}/suspended PUT /process-definition/key/{key}/tenant-id/{tenant-id}/suspended Activate/Suspend By Key PUT /process-definition/suspended ''' # proces instance Variables def batch_get(self, batchId=None): '''Quuery tasks :param batchId: STRING Filter by batch id. ''' path = '/batch/'+batchId return self.client.run_http_request2( path, 'GET') @staticmethod def typefrompyton(val): """ return the type definition for val :param val a object: """ if isinstance(val, basestring): return "String" elif isinstance(val, bool): return "Boolean" elif isinstance(val, int): return "Integer" elif isinstance(val, long): return "Long" elif isinstance(val, float): return "Double" elif isinstance(val, datetime.date): return "Date" else: return "Object" @staticmethod def variablesfrompyton(pvars): """ convert a dictionary into a camunda variables rappresentation @param pvars dict the dictionary containing variables see https://docs.camunda.org/manual/7.4/user-guide/process-engine/variables/ camunda supported object are: boolean: Instances of java.lang.Boolean bytes: Instances of byte[] short: Instances of java.lang.Short integer: Instances of java.lang.Integer long: Instances of java.lang.Long double: Instances of java.lang.Double date: Instances of java.util.Date string: Instances of java.lang.String null: null references file object json xml """ try: ret = {} for name in pvars: variable = {'value': pvars[name], 'type': None} if isinstance(pvars[name], basestring): variable['type'] = "String" elif isinstance(pvars[name], bool): variable['type'] = "Boolean" elif isinstance(pvars[name], int): variable['type'] = "Integer" elif isinstance(pvars[name], long): variable['type'] = "Long" elif isinstance(pvars[name], float): variable['type'] = "Double" elif isinstance(pvars[name], datetime.date): variable['type'] = "Date" ret[name] = variable pass except Exception as ex: logger = getLogger('behive_bpm') logger.error(ex) return {'variables': ret} @staticmethod def variablestopyton(variables): """ convert a dictionary into a camunda variables rappresentation see https://docs.camunda.org/manual/7.4/user-guide/process-engine/variables/ camunda supported object are: boolean: Instances of java.lang.Boolean bytes: Instances of byte[] short: Instances of java.lang.Short integer: Instances of java.lang.Integer long: Instances of java.lang.Long double: Instances of java.lang.Double date: Instances of java.util.Date string: Instances of java.lang.String null: null references file object json xml """ try: if not 'variables' in variables: ret = None raise Exception( 'variables not present in dictionary while converting to python') pvars = variables['variables'] ret = {} for name in pvars: ret[name] = pvars[name]['value'] vtype = pvars[name]['type'] if vtype == "String": ret[name] = str(ret[name]) elif vtype == "Boolean": ret[name] = bool(ret[name]) elif vtype == "Long": ret[name] = long(ret[name]) elif vtype == "Short" or vtype == "Integer": ret[name] = int(ret[name]) elif vtype == "Double": ret[name] = float(ret[name]) elif vtype == "Date": ret[name] = datetime.date(ret[name]) elif vtype == "Null": ret[name] = None except Exception as ex: logger = getLogger('behive_bpm') logger.error(ex) ret = None return ret def incidents(self): ''' return the list of the incidents http://10.102.160.12:9090/engine-rest/incident Get List GET /incident Get List Count GET /incident/count ''' pass # external task api def externaltask_get(self, taskid): """ Get GET /external-task/{id} get external task |Name |Value |Description |activityId |String |The id of the activity that this external task belongs to. |activityInstanceId |String |The id of the activity instance that the external task belongs to. |errorMessage |String |The error message that was supplied when the last failure of this task was reported. |executionId |String |The id of the execution that the external task belongs to. |id |String |The id of the external task. |lockExpirationTime |String |The date that the task's most recent lock expires or has expired. |processDefinitionId |String |The id of the process definition the external task is defined in. |processDefinitionKey|String |The key of the process definition the external task is defined in. |processInstanceId |String |The id of the process instance the external task belongs to. |tenantId |String |The id of the tenant the external task belongs to. |retries |Number |The number of retries the task currently has left. |suspended |Boolean|A flag indicating whether the external task is suspended or not. |workerId |String |The id of the worker that posesses or posessed the most recent lock. |priority |Number |The priority of the external task. |topicName |String |The topic name of the external task. """ path = self.baseurl + '/external-tasky/' + taskid task = self.client.run_http_request2(path, 'GET') return BpmnExternalTask(self, **task) def __ext_task_qry(self, path, **kwargs): """ execute a query post """ att_filter = {} for item in self.ext_task_queryitem: if item in kwargs: att_filter[item] = kwargs[item] # head = {'Content-Type': 'application/json'} data = json.encode(att_filter) result = self.client.run_http_request2( path, 'POST', data=data, headers={'Content-Type': 'application/json'}) return result def externaltask_query(self, **kwargs): """ Get List GET /external-task Get List (POST) POST /external-task Get List Count (POST) query external task """ result = self.__ext_task_qry('/external-task', **kwargs) return [BpmnExternalTask(self, **res) for res in result] def externaltask_count(self, **kwargs): """ Get List Count GET /external-task/count POST /external-task/count """ result = self.__ext_task_qry('/external-task/count', **kwargs) if 'count' in result: return result['count'] else: return 0 def externaltask_fetch_and_lock(self, workerid, maxtasks, topicname, usepriority=True, lockduration=360000): """ Fetch and Lock POST /external-task/fetchAndLock """ att = { "workerId": workerid, "maxTasks": maxtasks, "usePriority": usepriority, "topics": [{"topicName": topicname, "lockDuration": lockduration, }] } # head = {'Content-Type': 'application/json'} data = json.encode(att) result = self.client.run_http_request2( '/external-task/fetchAndLock', 'POST', data=data, headers={'Content-Type': 'application/json'}) return [BpmnExternalTask(self, workerid=workerid, **res) for res in result] def externaltask_complete(self, taskid, workerid, pvars=None): """ Complete POST /external-task/{id}/complete """ if pvars is not None: att = self.variablesfrompyton(pvars) else: att = {} att["workerId"] = workerid data = json.encode(att) url = '/external-task/%s/complete' % taskid self.client.run_http_request2( url, 'POST', data=data, headers={'Content-Type': 'application/json'}) return True def externaltask_error(self, taskid, workerid, errorcode): """ Handle BPMN Error POST /external-task/{id}/bpmnError """ att = { "workerId": workerid, "errorCode": errorcode } data = json.encode(att) url = '/external-task/%s/bpmnError' % taskid self.client.run_http_request2( url, 'POST', data=data, headers={'Content-Type': 'application/json'}) return True def externaltask_failure(self, taskid, workerid, errormsg, errordetail=None, retries=3, timeout=60000): """ Handle Failure POST /external-task/{id}/failure """ att = { "workerId": workerid, "errorMessage": "Does not compute", "retries": retries, "retryTimeout": timeout } if isinstance(errordetail, str): att['errorDetails'] = errordetail data = json.encode(att) url = '/external-task/%s/failure' % taskid self.client.run_http_request2( url, 'POST', data=data, headers={'Content-Type': 'application/json'}) return True def externaltask_unlock(self, taskid): """ Unlock POST /external-task/{id}/unlock """ url = '/external-task/%s/unlock' % taskid self.client.run_http_request2(url, 'POST',) return True def externaltask_priority(self, taskid, priority): """ Set Priority PUT /external-task/{id}/priority """ data = '{"priority":%i}' % int(priority) url = '/external-task/%s/priority' % taskid self.client.run_http_request2( url, 'PUT', data=data, headers={'Content-Type': 'application/json'}) return True def externaltask_retries(self, taskid, retries): """ Set Retries PUT /external-task/{id}/retries """ data = '{"retries":%i}' % int(retries) url = '/external-task/%s/retries' % taskid self.client.run_http_request2( url, 'PUT', data=data, headers={'Content-Type': 'application/json'}) return True