conductor-worker-python/pyexecplugins/pyexecplugins.py

226 lines
7.5 KiB
Python

import requests;
import json
class PyExecPlugins(type):
def __init__(cls, name, bases, attrs):
if not hasattr(cls, "plugins"):
#print("Initializing plugins")
cls.plugins = {}
cls.alias = {}
else:
#print("Appending a plugin ", cls.name, cls)
cls.plugins[cls.name] = cls
#Alias plugin also with taskdefinition so it will be lookup-able with poth Operation name and taskdefinition
if cls.taskdef is not None:
cls.alias[cls.taskdef["name"]] = cls
def getPlugins(cls):
return cls.plugins
def getPluginNames(cls):
return [*cls.plugins.keys()]
def get(cls, name):
return cls.plugins.get(name)
def getAlias(cls, name):
return cls.alias.get(name)
def registerTaskDefinitions(cls, server):
url = server + "/metadata/taskdefs"
#pyexec generic taskdefinition
taskdefs = [
{
"name" : "pyexec",
"description" : "Execute PyExec operations",
"inputKeys" : ["operation"],
"outputKeys" : ["ret"],
"ownerEmail" : "m.lettere@gmail.com"
}
]
for plg in cls.getPluginNames():
if cls.plugins[plg].taskdef is not None:
taskdef = cls.plugins[plg].taskdef
taskdefs.append(taskdef)
#Post all new (or not) task definitions to orchestrator
headers = {'Content-Type': 'application/json'}
try:
response = requests.request("POST", url, headers=headers, data=json.dumps(taskdefs))
except Exception as e:
print("Unable to register task defs", e)
class PyExecPlugin(object, metaclass=PyExecPlugins):
def __init__(self, data=None):
self.data = data
def supportsStandalone(self):
return (self.taskdef is not None)
class Nop(PyExecPlugin):
name = "Nop"
taskdef = None
def __init__(self, data=None):
super().__init__(data)
def execute(self):
return None
class Identity(PyExecPlugin):
name = "Identity"
taskdef = None
def __init__(self, data=None):
super().__init__(data)
def execute(self):
self.data.pop("_result", None)
return self.data
class Sequence(PyExecPlugin):
name = "Sequence"
taskdef = None
def __init__(self, data=None):
super().__init__(data)
def handleSequence(self, sequence, currentresults):
for t in sequence:
operation = t.get("operation", "Nop")
if operation == "Sequence":
self.handleSequence(t.tasks, self.results)
else:
p = PyExecPlugin.get(operation)
if p != None:
t["_result"] = currentresults
pi = p(t)
ret = pi.execute()
self.result.append(ret)
else: raise Exception("Operation {} not found.".format(operation))
def execute(self):
self.result = []
self.handleSequence(self.data.get("tasks",[]),self.result)
return {"result": self.result}
#class Http(PyExecPlugin):
# name = "Http"
#
# def __init__(self, data):
# super().__init__(data)
# self.method = data.get("method") or "get"
# self.url = data.get("url")
# self.headers = data.get("headers") or {}
# self.contenttype = self.headers.get("Content-Type")
# self.accept = self.headers.get("Accept")
# self.body = data.get("body")
# self.params = data.get("params")
# self.expect = data.get("expect")
# self.fail = data.get("fail")
#
# def doRequest(self):
# #print(self.method, self.url, self.contenttype, self.accept)
# if self.contenttype != None and self.contenttype.find("json") != -1:
# self.response = requests.request(self.method, self.url, headers=self.headers, json = self.body)
# else:
# self.response = requests.request(self.method, self.url, headers=self.headers, data = self.body, params = self.params)
# return self.response
#
# def computeStatus(self):
# if self.fail == False:
# return "COMPLETED"
# elif self.expect == None:
# return "COMPLETED" if self.response.ok else "FAILED"
# else:
# if type(self.expect) == list:
# return "COMPLETED" if (self.response.status_code in self.expect) else "FAILED"
# else:
# return "COMPLETED" if (self.response.status_code == self.expect) else "FAILED"
#
# def buildOutput(self, status):
# hdrs = {}
# for k in self.response.headers.keys(): hdrs[k] = self.response.headers[k]
#
# print("Response: {} {}".format(self.response.status_code, self.response.reason))
#
# if hdrs.get("Content-Type") != None and hdrs["Content-Type"].find("json") != -1 or self.accept != None and #self.accept.find("json") != -1:
# outbody = self.response.json() if len(self.response.content) != 0 else None
# else:
# outbody = self.response.text
# #print(outbody)
# return {
# 'status': status,
# 'output': {
# "body" : outbody,
# "headers" : hdrs,
# "status" : self.response.status_code,
# "reason" : self.response.reason
# },
# 'logs': ['one', 'two']
# }
#
# def execute(self):
# self.doRequest()
# status = self.computeStatus()
# return self.buildOutput(status)
#class Eval(PyExecPlugin):
# name = "Eval"
#
# def __init__(self, data=None):
# super().__init__(data)
#
# def execute(self):
# code = self.data.get("code")
# if code != None:
# ret = eval(code, { "data" : self.data})
# return { "result" : ret }
#class Write(PyExecPlugin):
# name = "Write"
#
# def __init__(self, data=None):
# super().__init__(data)
#
# def execute(self):
# print("File opening at", self.data["path"])
# fo = open(self.data["path"], "w")
# print("File opened", fo)
# typ = self.data.get("type", "text")
# if typ == "json":
# fo.write(json.dumps(self.data.get("content","{}")))
# else:
# fo.write(self.data.get("content", ""))
# fo.close()
# return {}
#class Shell(PyExecPlugin):
# name = "Shell"
#
# def __init__(self, data=None):
# super().__init__(data)
#
# def execute(self):
# output = {
# 'results' : [],
# 'status' : "COMPLETED"
# }
# for cmdentry in self.data.get("commands"):
# expect = cmdentry.get("expect", 0)
# cmd = cmdentry.get("line")
# #Use shell=True for very complex cmdlines that do have quotes and ther amenities
# withshell = cmdentry.get("withshell", self.data.get("withshell", False))
# if cmd == None:
# continue
# else:
# cmd = cmd.split() if not withshell else cmd
# print("Going to execute", withshell, cmd)
# completed = subprocess.run(cmd, shell=withshell, capture_output=True, text=True)
# output["results"].append({ 'returncode' : completed.returncode, 'stdout' : completed.stdout, 'stderr': completed.stderr})
# if completed.returncode != expect:
# output["status"] = "FAILED"
# break
# return output