def wmGetRecurringPlan(self): sScheduleID = uiCommon.getAjaxArg("sScheduleID") # tracing this backwards, if the action_plan table has a row marked "schedule" but no schedule_id, problem. if not sScheduleID: uiCommon.log("Unable to retrieve Reccuring Plan - schedule id argument not provided.") sched = {} # now we know the details, go get the timetable for that specific schedule sSQL = """select schedule_id, months, days, hours, minutes, days_or_weeks, label from action_schedule where schedule_id = %s""" dr = self.db.select_row_dict(sSQL, (sScheduleID)) if dr: sDesc = (dr["schedule_id"] if not dr["label"] else dr["label"]) sched["sDescription"] = sDesc sched["sMonths"] = dr["months"] sched["sDays"] = dr["days"] sched["sHours"] = dr["hours"] sched["sMinutes"] = dr["minutes"] sched["sDaysOrWeeks"] = str(dr["days_or_weeks"]) else: uiCommon.log("Unable to find details for Recurring Action Plan. " + self.db.error + " ScheduleID [" + sScheduleID + "]") return json.dumps(sched)
def wmSavePlan(self): iPlanID = uiCommon.getAjaxArg("iPlanID") sParameterXML = uiCommon.getAjaxArg("sParameterXML") iDebugLevel = uiCommon.getAjaxArg("iDebugLevel") """ * JUST AS A REMINDER: * There is no parameter 'merging' happening here. This is a Plan ... * it has ALL the parameters it needs to pass to the CE. * * """ if not iPlanID: uiCommon.log("Missing Action Plan ID.") # we encoded this in javascript before the ajax call. # the safest way to unencode it is to use the same javascript lib. # (sometimes the javascript and .net libs don't translate exactly, google it.) sParameterXML = uiCommon.unpackJSON(sParameterXML) # we gotta peek into the XML and encrypt any newly keyed values sParameterXML = task.Task.PrepareAndEncryptParameterXML(sParameterXML) sSQL = """update action_plan set parameter_xml = %s, debug_level = %s where plan_id = %s""" self.db.exec_db(sSQL, (sParameterXML, iDebugLevel if iDebugLevel > -1 else None, iPlanID)) return json.dumps({"result": "success"})
def wmSearch(self): """ This function will eventually have lots of flexibility based on the 'type' and 'in' parameters. For the moment we're starting with the ability to search Task function_xml for the pattern. NOTE: MySql sucks at xml, so if we need to work with an xml object it's faster to retrieve every row and then iterate. So we'll have to apply a 'like' clause first to limit the set, then work with it. """ _type = uiCommon.getAjaxArg("type") _in = uiCommon.getAjaxArg("in") _pattern = uiCommon.getAjaxArg("pattern") out = {} if _type == "task": # bare essentials - is the pattern in the function_xml column where_clause = "where (function_xml like '%%{0}%%')".format(_pattern) sql = """select t.task_id, t.task_name, t.version, s.codeblock_name, s.step_id, s.step_order, s.function_name, s.function_xml from task_step s join task t on s.task_id = t.task_id %s""" % (where_clause) uiCommon.log(sql) rows = self.db.select_all_dict(sql) rows = list(rows) if rows else [] out["results"] = rows else: out["error"] = "Invalid search 'type'" return catocommon.ObjectOutput.AsJSON(out)
def wmDeleteActionPlan(self): iPlanID = uiCommon.getAjaxArg("iPlanID") if iPlanID < 1: uiCommon.log("Missing Action Plan ID.") return "Missing Action Plan ID." task.Task.DeletePlan(iPlanID) # if we made it here, so save the logs uiCommon.WriteObjectDeleteLog(catocommon.CatoObjectTypes.Schedule, "", "", "Action Plan [" + iPlanID + "] deleted.") return json.dumps({"result": "success"})
def wmDeleteSchedule(self): sScheduleID = uiCommon.getAjaxArg("sScheduleID") if not sScheduleID: uiCommon.log("Missing Schedule ID.") return "Missing Schedule ID." task.Task.DeleteSchedules(sScheduleID) # if we made it here, so save the logs uiCommon.WriteObjectDeleteLog(catocommon.CatoObjectTypes.Schedule, "", "", "Schedule [" + sScheduleID + "] deleted.") return json.dumps({"result": "success"})
def wmRestartService(self): """ Restarts a specific service. """ user_role = uiCommon.GetSessionUserRole() if user_role != "Administrator": raise Exception("Only Administrators can restart services.") component = uiCommon.getAjaxArg("component") uiCommon.log("Service Restart!", 3) os.system("$CSK_HOME/cato/services/restart_specific.sh %s" % (component)) return json.dumps({"result": "success"})
def wmHTTPGet(self): """Simply proxies an HTTP GET to another domain, and returns the results.""" url = uiCommon.getAjaxArg("url") try: result, err = catocommon.http_get(url, 15) if err: return "External HTTP request failed. %s" % err except: uiCommon.log("Error during HTTP GET." + traceback.format_exc()) return traceback.format_exc() return result
def wmSaveSchedule(self): sScheduleID = uiCommon.getAjaxArg("sScheduleID") aMonths = uiCommon.getAjaxArg("sMonths") aDays = uiCommon.getAjaxArg("sDays") aHours = uiCommon.getAjaxArg("sHours") aMinutes = uiCommon.getAjaxArg("sMinutes") sDaysOrWeeks = uiCommon.getAjaxArg("sDaysOrWeeks") sParameterXML = uiCommon.getAjaxArg("sParameterXML") iDebugLevel = uiCommon.getAjaxArg("iDebugLevel") """ * JUST AS A REMINDER: * There is no parameter 'merging' happening here. This is a Scheduled Plan ... * it has ALL the parameters it needs to pass to the CE. * * """ if not sScheduleID or not aMonths or not aDays or not aHours or not aMinutes or not sDaysOrWeeks: uiCommon.log("Missing Schedule ID or invalid timetable.") # we encoded this in javascript before the ajax call. # the safest way to unencode it is to use the same javascript lib. # (sometimes the javascript and .net libs don't translate exactly, google it.) sParameterXML = uiCommon.unpackJSON(sParameterXML) # we gotta peek into the XML and encrypt any newly keyed values sParameterXML = task.Task.PrepareAndEncryptParameterXML(sParameterXML) # whack all plans for this schedule, it's been changed sSQL = "delete from action_plan where schedule_id = '" + sScheduleID + "'" self.db.exec_db(sSQL) # figure out a label sLabel, sDesc = catocommon.GenerateScheduleLabel(aMonths, aDays, aHours, aMinutes, sDaysOrWeeks) sSQL = "update action_schedule set" \ " months = '" + ",".join([str(x) for x in aMonths]) + "'," \ " days = '" + ",".join([str(x) for x in aDays]) + "'," \ " hours = '" + ",".join([str(x) for x in aHours]) + "'," \ " minutes = '" + ",".join([str(x) for x in aMinutes]) + "'," \ " days_or_weeks = '" + sDaysOrWeeks + "'," \ " label = " + ("'" + sLabel + "'" if sLabel else "null") + "," \ " descr = " + ("'" + sDesc + "'" if sDesc else "null") + "," \ " parameter_xml = " + ("'" + catocommon.tick_slash(sParameterXML) + "'" if sParameterXML else "null") + "," \ " debug_level = " + (iDebugLevel if iDebugLevel > -1 else "null") + \ " where schedule_id = '" + sScheduleID + "'" self.db.exec_db(sSQL)
def wmGetActionPlans(self): sTaskID = uiCommon.getAjaxArg("sTaskID") try: sHTML = "" t = task.Task() t.FromID(sTaskID) plans = t.GetPlans() for dr in plans: sHTML += '''<div class="ui-widget-content ui-corner-all pointer clearfloat action_plan" id="ap_%s" plan_id="%s" run_on="%s" source="%s" schedule_id="%s">''' % (str(dr["PlanID"]), str(dr["PlanID"]), str(dr["RunOn"]), dr["Source"], str(dr["ScheduleID"])) sHTML += " <div class=\"floatleft action_plan_name\">" # an icon denotes if it's manual or scheduled if dr["Source"] == "schedule": sHTML += "<span class=\"floatleft ui-icon ui-icon-calculator\" title=\"Scheduled\"></span>" else: sHTML += "<span class=\"floatleft ui-icon ui-icon-document\" title=\"Run Later\"></span>" sHTML += dr["RunOn"] sHTML += " </div>" sHTML += " <div class=\"floatright\">" sHTML += "<span class=\"ui-icon ui-icon-trash action_plan_remove_btn\" title=\"Delete Plan\"></span>" sHTML += " </div>" sHTML += " </div>" return sHTML except Exception: uiCommon.log(traceback.format_exc())
def wmCreateObjectFromXML(self): """Takes a properly formatted XML backup file, and imports each object.""" inputtext = uiCommon.getAjaxArg("import_text") inputtext = uiCommon.unpackJSON(inputtext) on_conflict = uiCommon.getAjaxArg("on_conflict") # the trick here is to return enough information back to the client # to best interact with the user. # what types of things were in this backup? what are their new ids? items = [] # parse it as a validation, and to find out what's in it. xd = None js = None try: xd = catocommon.ET.fromstring(inputtext) except catocommon.ET.ParseError: try: js = json.loads(inputtext) except: return json.dumps({"error": "Data is not properly formatted XML or JSON."}) if xd is not None: # so, what's in here? Tasks? # TASKS for xtask in xd.findall("task"): uiCommon.log("Importing Task [%s]" % xtask.get("name", "Unknown")) t = task.Task() t.FromXML(catocommon.ET.tostring(xtask), on_conflict) # NOTE: possible TODO # passing a db connection to task.DBSave will allow rollback of a whole # batch of task additions. # if it's determined that's necessary here, just create a db connection here # and pass it in result, err = t.DBSave() if result: # add security log uiCommon.WriteObjectAddLog(catocommon.CatoObjectTypes.Task, t.ID, t.Name, "Created by import.") items.append({"type": "task", "id": t.ID, "name": t.Name}) else: if err: items.append({"type": "task", "id": t.ID, "name": t.Name, "info": err}) else: items.append({"type": "task", "id": t.ID, "name": t.Name, "error": "Unable to create Task. No error available."}) # otherwise it might have been JSON elif js is not None: # if js isn't a list, bail... if not isinstance(js, list): js = [js] for jstask in js: uiCommon.log("Importing Task [%s]" % jstask.get("Name", "Unknown")) t = task.Task() t.FromJSON(json.dumps(jstask), on_conflict) result, err = t.DBSave() if result: # add security log uiCommon.WriteObjectAddLog(catocommon.CatoObjectTypes.Task, t.ID, t.Name, "Created by import.") items.append({"type": "task", "id": t.ID, "name": t.Name}) else: if err: items.append({"type": "task", "id": t.ID, "name": t.Name, "info": err}) else: items.append({"type": "task", "id": t.ID, "name": t.Name, "error": "Unable to create Task. No error available."}) else: items.append({"info": "Unable to create Task from backup JSON/XML."}) # TODO: for loop for Assets will go here, same logic as above # ASSETS return json.dumps({"items": items})
def wmAnalyzeImportXML(self): """Takes a properly formatted XML backup file, and replies with the existence/condition of each Task.""" inputtext = uiCommon.getAjaxArg("import_text") inputtext = uiCommon.unpackJSON(inputtext) on_conflict = uiCommon.getAjaxArg("on_conflict") # the trick here is to return enough information back to the client # to best interact with the user. # what types of things were in this backup? what are their new ids? items = [] # parse it as a validation, and to find out what's in it. xd = None js = None try: xd = catocommon.ET.fromstring(inputtext) except catocommon.ET.ParseError as ex: uiCommon.log("Data is not valid XML... trying JSON...") try: js = json.loads(inputtext) except Exception as ex: uiCommon.log(ex) return json.dumps({"error": "Data is not properly formatted XML or JSON."}) # if the submitted data was XML if xd is not None: # so, what's in here? Tasks? # TASKS for xtask in xd.findall("task"): t = task.Task() t.FromXML(catocommon.ET.tostring(xtask)) if t.DBExists and t.OnConflict == "cancel": msg = "Task exists - set 'on_conflict' attribute to 'replace', 'minor' or 'major'." elif t.OnConflict == "replace": msg = "Will be replaced." elif t.OnConflict == "minor" or t.OnConflict == "major": msg = "Will be versioned up." else: msg = "Will be created." items.append({"type": "task", "id": t.ID, "name": t.Name, "info": msg}) # otherwise it might have been JSON elif js is not None: # if js isn't a list, bail... if not isinstance(js, list): return json.dumps({"error": "JSON data must be a list of Tasks."}) for jstask in js: t = task.Task() t.FromJSON(json.dumps(jstask), on_conflict) if t.DBExists and t.OnConflict == "cancel": msg = "Task exists - set OnConflict to 'replace', 'minor' or 'major'." elif t.OnConflict == "replace": msg = "Will be replaced." elif t.OnConflict == "minor" or t.OnConflict == "major": msg = "Will be versioned up." else: msg = "Will be created." items.append({"type": "task", "id": t.ID, "name": t.Name, "info": msg}) else: items.append({"info": "Unable to create Task from backup JSON/XML."}) return json.dumps({"items": items})