Source code for cmd_cmod

import xml.parsers.expat,copy,base64,bindpyrame,re,ast,socket,threading,os

current_node=None
current_param=None
top_module=None
default_node=None
config_filename=None
module_dict={}

#********************* PYRAME FUNCTIONS **************************

def init():
    global default_node
    retcode,res=parse_file("/opt/pyrame/calxml_defaults.xml",None)
    if retcode==0:
        print("error in parsing default file...exiting")
        submod.exit(1)
    default_node=top_module

#pyrapi:reload_default_cmod:
[docs]def reload_default_cmod(): """reload the default parameters file""" global default_node,top_module default_node=None retcode,res=parse_file("/opt/pyrame/calxml_defaults.xml",None) if retcode==0: default_node=top_module=None return 0,"parse error" default_node=top_module return 1,"ok"
#pyrapi:load_config_file_cmod:filename
[docs]def load_config_file_cmod(filename): """load a configuration from an xml file""" global top_module,config_filename,default_node checkxml=os.system("xmllint %s 2>&1 > /dev/null"%(filename)) if checkxml!=0: return 0,"syntax error in xml file %s"%(filename) retcode,res=parse_file(filename,default_node) if retcode==0: top_module=None config_filename=None return 0,"parse error : %s"%(res) config_filename=filename retcode,res=top_module.register() if retcode==0: return 0,"cant register modules : %s"%(res) return 1,"ok"
#pyrapi:get_config_origin_cmod: def get_config_origin_cmod(): global top_module,config_filename if top_module.type=="defaultConfig": # GUIs depend on this exact response return 1,"None" if config_filename==None: return 1,"serialized config" return 1,config_filename #pyrapi:gener_config_cmod:
[docs]def gener_config_cmod(): """extract the configuration from the tree and aggregate it in a XML file""" res="<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+top_module.export_xml() return 1,res
#pyrapi:gener_configb64_cmod:
[docs]def gener_configb64_cmod(): """extract the configuration from the tree and aggregate it in a XML file encoded in base 64""" res="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+top_module.export_pretty_xml(" ") return 1,base64.b64encode(res)
#pyrapi:save_config_cmod:filename def save_config_cmod(filename): if not filename.endswith(".xml"): filename+=".xml" retcode,res=gener_configb64_cmod() with open(filename,"w") as f: f.write(base64.b64decode(res)) return 1,"ok" #thread to apply a sequence of phases asynchronously def transition_t(bg_context,node,goto,transition_name,transition_fallback,params_dict): retcode,res=command_cmod(node.name,"false","get_seq_transition_"+node.type,transition_name,goto) if retcode==0: submod_sendres(bg_context,0,"error getting transition phases from top_module: %s"%(res)) return if res!="": phases=res.split(",") for phase in phases: retcode,res=node.apply_phase(phase,params_dict) if retcode==0: init_error=res if transition_fallback!="undef": retcode,res=command_cmod(node.name,"false","get_seq_transition_"+node.type,transition_fallback,"1") if res!="": phases=res.split(",") for phase in phases: retcode,res=node.apply_phase(phase,params_dict) submod_sendres(bg_context,0,init_error) return submod_sendres(bg_context,1,"ok") def apply_phase_t(bg_context,node,phase_name,params_dict): retcode,res=node.apply_phase(phase_name,params_dict) submod_sendres(bg_context,retcode,res)
[docs]def apply_phase_cmod(dev_name,phase_name,params=""): """apply a phase with name phase_name on the subtree with root dev_name. params is an empty string or a json dictionary containing values that can be passed to modules during the phase""" try: node=module_dict[dev_name] except: return 0,"unknown device %s"%(dev_name) #convert external params string to dictionary if params!="": params_dict=ast.literal_eval(params) else: params_dict={} #launch a thread to apply the necessary phases retcode,res=submod_bgcontext() t=threading.Thread(target=apply_phase_t,args=(res,node,phase_name,params_dict)) t.start() #finish synchronous part return KEEPOPEN,"ok"
#pyrapi:transition_cmod:goto,transition_name,transition_fallback,params
[docs]def transition_cmod(dev_name,goto,transition_name,transition_fallback,params=""): "Use *transition_name* to a system described by the loaded configuration. If the transition fails, use *transition_fallback*. The optional JSON-encoded *params* value adds named parameters to the phases." #check that the node exists try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) #convert external params string to dictionary if params!="": params_dict=ast.literal_eval(params) else: params_dict={} #launch a thread to apply the necessary phases retcode,res=submod_bgcontext() t=threading.Thread(target=transition_t,args=(res,node,goto,transition_name,transition_fallback,params_dict)) t.start() #finish synchronous part return KEEPOPEN,"ok"
def sendcmd_t(bg_context,ip,port,func,name,params): retcode,res=bindpyrame.sendcmd(ip,port,func,name,*params) submod_sendres(bg_context,retcode,res) #pyrapi:command_cmod:dev_name,async,func,*params
[docs]def command_cmod(dev_name,async,func,*params): """apply a command on a device. If async is true, the command is done asynchronously.""" try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) if sbool(async): retcode,res=submod_bgcontext() t=threading.Thread(target=sendcmd_t,args=(res,node.ip,node.port,func,node.name,params)) t.start() #finish synchronous part return KEEPOPEN,"ok" else: return bindpyrame.sendcmd(node.ip,node.port,func,node.name,*params)
#pyrapi:set_param_cmod:dev_name,param_name,param_value
[docs]def set_param_cmod(dev_name,param_name,param_value): """add or modify a parameter for a device""" try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) else: try: test=node.effective_params[param_name] except: test=None if test==None: return 0,"unknown parameter %s for device %s"%(param_name,dev_name) node.effective_params[param_name]=param_value return 1,"ok"
#pyrapi:get_param_cmod:dev_name,param_name
[docs]def get_param_cmod(dev_name,param_name): """get a parameter from a device""" try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) else: if param_name in node.effective_params: return 1,node.effective_params[param_name] else: return 0,"unknown param %s"%(param_name)
#pyrapi:get_type_cmod:dev_name
[docs]def get_type_cmod(dev_name): """find the type of a device""" try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) else: return 1,node.type
#pyrapi:get_ip_cmod:dev_name
[docs]def get_ip_cmod(dev_name): """find the ip of a device""" try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) else: return 1,node.ip
#pyrapi:get_location_cmod:dev_name
[docs]def get_location_cmod(dev_name): "get ip and type of a device" try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) else: return 1,"%s,%s"%(node.ip,node.type)
#pyrapi:get_name_list_cmod:dev_type
[docs]def get_name_list_cmod(dev_type): """get the list of all device names of a *dev_type*""" return 1,",".join(top_module.enumerate(dev_type))
#pyrapi:get_name_sublist_cmod:dev_type,parent_name
[docs]def get_name_sublist_cmod(dev_type,parent_name): """get the list of device names of a *dev_type* type with *parent_name* parent""" try: node=module_dict[parent_name] except: node=None if node==None: return 0,"unknown device %s"%(parent_name) return 1,",".join(node.enumerate(dev_type))
#pyrapi:get_config_list_cmod: def get_config_list_cmod(): conf_path="/opt/pyrame/config" lf=os.listdir(conf_path) res=[] for f in lf: if f.endswith(".xml"): res.append("%s/%s"%(conf_path,f)) return 1,",".join(res) #pyrapi:is_enabled_cmod:dev_name def is_enabled_cmod(dev_name): try: node=module_dict[dev_name] except: node=None if node==None: return 0,"unknown device %s"%(dev_name) return 1,str(node.enabled) #********************* PARSER FUNCTIONS ************************** def parser_opening_tag(tag,attributes): global current_node,top_module,module_dict,current_param if tag=="param": current_param=attributes["name"] current_node.legacy_params[current_param]="" else: #creating a new node if "name" not in attributes: print("error : object %s with no name"%(tag)) name="undef" else: name=attributes["name"] if name in module_dict: print("error : object %s is duplicated"%(name)) enabled=1 if "disabled" in attributes: if sbool(attributes["disabled"])==1: enabled=0 else: enabled=1 if "vital" in attributes: vital=int(attributes["vital"]) else: vital=1 print("new node %s"%(name)) newnode=node(current_node,tag,name,vital,enabled) current_node=newnode if top_module==None: top_module=newnode module_dict[name]=newnode def parser_closing_tag(tag): global current_node,current_param if tag=="param": current_param=None else: if current_node.parent!=None: current_node.parent.children.append(current_node) current_node.create_implicit() #print("closing node %s"%(current_node.name)) current_node=current_node.parent def parser_data(value): global current_node if current_param!=None: current_node.legacy_params[current_param]=value #print("filling param %s with %s"%(current_param,value)) else: print("error param value outside param value=%s"%(value)) def strip_file(filename): try: file=open(filename,'read') content="" for line in file.readlines(): content+=line.strip() file.close() return content except: print("error : unknown file %s"%(filename)) return "" def parse_file(filename,root): #clean global variables global current_node,current_param,top_module,default_node,module_dict current_node=default_node current_param=None top_module=None if default_node!=None: default_node.children=[] module_dict={} #parse the file parser=xml.parsers.expat.ParserCreate() parser.StartElementHandler=parser_opening_tag parser.EndElementHandler=parser_closing_tag parser.CharacterDataHandler=parser_data content=strip_file(filename) if content=="": return 0,"unknown file %s"%(filename) try: parser.Parse(content) except Exception as e: print("syntax error : %s"%(str(e))) return 0,str(e) #compute all effective or secondary parameters top_module.calc_effective_params() module_dict["root"]=top_module return 1,"ok" #********************* INTERNAL FUNCTIONS ****************** #********************* NODE CLASS ************************** class node: def __init__(self,parent,type,name,vital,enabled): self.parent=parent #contain the parent node self.name=name #the name of the node (corresponding to the name attribute in xml file) self.type=type #the type of the node (corresponding to the tag in xml file) self.port=submod.getport(self.type) #contain the numeric port of the node if self.name.startswith(self.type): self.postfix=self.name[len(self.type):] else: self.postfix="_"+self.name if parent!=None: self.legacy_params=copy.deepcopy(self.parent.legacy_params) else: self.legacy_params={} #dictionary containing all the param from file + all params inherited from parent node self.effective_params={} #dictionary containing the effective values of the parameters (after calculation of formulae) self.vital=vital #flag indicating if this node is vital for the system self.enabled=enabled # flag indicating if this node is disabled self.children=[] #contain a list of the children nodes self.port=-1 def register(self): if self.type!="domain": #print("register module %s at %s:%d"%(self.name,self.ip,self.port)) retcode,res=bindpyrame.sendcmd(self.ip,self.port,"register_module") if retcode==0: print("error : cant register %s : %s"%(self.name,res)) return 0,"cant register %s on port %d: %s"%(self.name,self.port,res) for c in self.children: retcode,res=c.register() if retcode==0: return 0,res return 1,"ok" def find_ip(self): if self.parent==None: return "127.0.0.1" if self.type=="domain": return socket.gethostbyname(self.effective_params["ip"]) return self.parent.find_ip() def enumerate(self,type): res=[] for c in self.children: res+=c.enumerate(type) if self.type==type: res.append(self.name) return res def count(self,type): if self.type==type: res=1 else: res=0 for c in self.children: res+=c.count(type) return res def create_implicit(self): for p in self.legacy_params: if "%s_nb_"%(self.type) in p: submodule="_".join(p.split("_")[2:]) if self.count(submodule)==0 and int(self.legacy_params[p])!=0: print("implicit creation for %d submodule %s"%(int(self.legacy_params[p]),submodule)) for i in range(1,int(self.legacy_params[p])+1): name=submodule+self.postfix+"_%d"%(i) newchild=node(self,submodule,name,self.vital,self.enabled) self.children.append(newchild) module_dict[name]=newchild newchild.create_implicit() def interpret(self,chain): interpret_regex=re.compile(r"\$\{[^\}]*\}") split_postfix=self.postfix.strip("_").split("_") hexa=False found=interpret_regex.findall(chain) interpreted=chain for f in found: #replace count type param if f[2:7]=="count": param=f[8:-2] cnt=top_module.count(param) interpreted=interpreted.replace(f,str(cnt)) continue #TODO add a $value(param_name) which replace the name by the value of the param #replace eval type param #print("replacing %s"%(f)) val=f[2:-1] #print("split postfix=",split_postfix) for i in range(1,len(split_postfix)+1): #print("replacing for i=%d"%(i)) if val.find('nx')>-1 or val.find('0x')>-1: hexa=True val=val.replace(("nd%s"%i),split_postfix[i-1]) val=val.replace(("nx%s"%i),split_postfix[i-1]) if hexa: interpreted=interpreted.replace(f,str(hex(eval(val)))[2:]) else: interpreted=interpreted.replace(f,str(eval(val))) return interpreted def calc_effective_params(self): #print("effective params calc for %s"%(self.type)) #interpret all relevant legacy params and insert them in effective params for p in self.legacy_params.keys(): if p[0:len(self.type)+1]==self.type+"_" in p: ep=p[len(self.type)+1:] self.effective_params[ep]=self.interpret(self.legacy_params[p]) #print("effective %s=%s"%(ep,self.effective_params[ep])) #get the ip and port of the module self.ip=self.find_ip() self.port=submod_getport(self.type) #print("ip:port for %s is %s:%d"%(self.name,self.ip,self.port)) #call the procedure on children for c in self.children: c.calc_effective_params() def apply_phase(self,phase_name,ext_params): #execute init apc command retcode,res=exec_apc(self,phase_name,ext_params,0) if retcode==0: if self.vital==0: return 1,"partial : %s"%(res) else: return 0,"fail : %s"%(res) #apply the phase on all children partial=0 partialmsg="" for c in self.children: retcode,res=c.apply_phase(phase_name,ext_params) if retcode==0: if self.vital==0: return 1,"partial : %s"%(res) else: return 0,"fail : %s"%(res) else: if res[0:7]=="partial": partial=1 if partialmsg=="": partialmsg=res else: partialmsg=partialmsg+","+msg #execute final apc command retcode,res=exec_apc(self,phase_name,ext_params,1) if retcode==0: #CAUTION : the module depend on this messages dont change their values if self.vital==0: return 1,"partial : %s"%(res) else: return 0,"fail : %s"%(res) #return final result if partial==1: return 1,"partial : %s"%(partialmsg) else: return 1,"full" def export_xml(self): res="<%s name=\"%s\">"%(self.type,self.name) for p in self.effective_params: if "nb_" not in p: res=res+"<param name=\"%s_%s\">%s</param>"%(self.type,p,self.effective_params[p]) for c in self.children: subres=c.export_xml() if subres!="": res=res+"%s"%(subres) res=res+"</%s>"%(self.type) return res def export_pretty_xml(self,indent): res="%s<%s name=\"%s\">\n"%(indent,self.type,self.name) for p in self.effective_params: if "nb_" not in p: res+="%s <param name=\"%s_%s\">%s</param>\n"%(indent,self.type,p,self.effective_params[p]) for c in self.children: res+=c.export_pretty_xml(indent+" ") res+="%s</%s>\n"%(indent,self.type) return res #********************* APC FUNCTIONS ****************** def apc_build_param_list(api,node,ext_params): #build the params list params=[] for a in api: if a=="dev_name": params.append(node.name) continue if a=="%s_id"%(node.type): params.append(node.name) continue if a=="parent": params.append(node.parent.name) continue if a=="childs": params.append(node.childs_name()) continue if a=="childs_details": params.append(node.childs_details()) continue if a=="nb_childs": params.append(node.nb_childs()) continue if a in ext_params: params.append(ext_params[a]) continue if a in node.effective_params: params.append(node.effective_params[a]) continue print("unknown param : %s"%(a)) return "unknown param : %s"%(a) return params
[docs]def exec_apc(node,phase_name,ext_params,fin): """this function apply a a phase to a device""" if node.type=="domain": return 1,"ok" if node.enabled==0: return 1,"ok" if fin: print("===> init_apc_fin for a %s with name %s on phase %s" %(node.type,node.name,phase_name)) else: print("===> init_apc for a %s with name %s on phase %s" %(node.type,node.name,phase_name)) #extract the function if fin==0: func="%s_%s"%(phase_name,node.type) else: func="%s_fin_%s"%(phase_name,node.type) #extract the api retcode,res=bindpyrame.sendcmd(node.ip,node.port,"getfuncapi_module",func) if retcode==0: print("no function with name %s in module %s"%(func,node.type)) return 1,"no function with that name" print("obtained api=%s for func %s"%(res,func)) api=res.split(",") #build the params list params=apc_build_param_list(api,node,ext_params) if type(params)==str: return 0,"error while executing %s <- %s"%(func,params) #send the command retcode,res=bindpyrame.sendcmd(node.ip,node.port,func,*params) #print("-->result %d,%s"%(retcode,res)) if retcode==0: return 0,"error while executing %s <- %s"%(func,res) else: return 1,"ok"