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