def generatePlans(update): """ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute. Returns: True: abort the plan generation process """ out.verbose("%r\n" % (update)) # Generate virt start script, stored in cache (key: 'virtPreamble') update.plans.addPlans(plangraph.RUNTIME_GET_VIRT_PREAMBLE, (config.dockerconfig.getVirtPreamble, )) # If the user specifies DHCP then we need to generate the config and store it to disk update.plans.addPlans(plangraph.RUNTIME_GET_VIRT_DHCP, (config.dhcp.getVirtDHCPSettings, )) update.plans.addPlans(plangraph.RUNTIME_SET_VIRT_DHCP, (config.dhcp.setVirtDHCPSettings, )) # Reload configuration files todoPlan = (config.configservice.reloadAll, ) abtPlan = [(config.osconfig.revertConfig, "dhcp"), (config.osconfig.revertConfig, "firewall"), (config.osconfig.revertConfig, "network"), (config.osconfig.revertConfig, "wireless"), (config.configservice.reloadAll, )] update.plans.addPlans(plangraph.RUNTIME_RELOAD_CONFIG, todoPlan, abtPlan) return None
def __init__(self, filename=None, reactor=None): if not filename: filename = settings.FC_CHUTESTORAGE_SAVE_PATH PDStorage.__init__(self, filename, reactor, settings.FC_CHUTESTORAGE_SAVE_TIMER) # Has it been loaded? if len(ChuteStorage.chuteList) == 0: out.verbose("Loading chutes from disk: %s\n" % (filename)) self.loadFromDisk()
def generatePlans(update): """ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute. Returns: True: abort the plan generation process """ out.verbose("%r\n" % (update)) # Detect system devices and set up basic configuration for them (WAN # interface, wireless devices). These steps do not need to be reverted on # abort. # # abortNetworkConfig is added as an abort command here so that it runs when # config.network.getNetworkConfig or just about anything else fails. # # reloadAll is added as an abort command here so that it runs when any of # the set* plans fail and back out. update.plans.addPlans(plangraph.STRUCT_GET_SYSTEM_DEVICES, (config.devices.getSystemDevices, ), (config.network.abortNetworkConfig, )) update.plans.addPlans(plangraph.STRUCT_SET_SYSTEM_DEVICES, (config.devices.setSystemDevices, ), (config.configservice.reloadAll, )) update.plans.addPlans(plangraph.STRUCT_GET_HOST_CONFIG, (config.hostconfig.getHostConfig, )) # Save current network configuration into chute cache (key: 'networkInterfaces') update.plans.addPlans(plangraph.STRUCT_GET_INT_NETWORK, (config.network.getNetworkConfig, )) # Setup changes to push into OS config files (key: 'osNetworkConfig') update.plans.addPlans(plangraph.STRUCT_GET_OS_NETWORK, (config.network.getOSNetworkConfig, )) # Setup changes to push into OS config files (key: 'osWirelessConfig') update.plans.addPlans(plangraph.STRUCT_GET_OS_WIRELESS, (config.wifi.getOSWirelessConfig, )) # Setup changes into virt configuration file (key: 'virtNetworkConfig') update.plans.addPlans(plangraph.STRUCT_GET_VIRT_NETWORK, (config.network.getVirtNetworkConfig, )) # Changes for networking todoPlan = (config.network.setOSNetworkConfig, ) abtPlan = (config.osconfig.revertConfig, 'network') update.plans.addPlans(plangraph.STRUCT_SET_OS_NETWORK, todoPlan, abtPlan) # Changes for wifi todoPlan = (config.wifi.setOSWirelessConfig, ) abtPlan = (config.osconfig.revertConfig, 'wireless') update.plans.addPlans(plangraph.STRUCT_SET_OS_WIRELESS, todoPlan, abtPlan) return None
def executePlans(update): """ Primary function that actually executes all the functions that were added to plans by all the exc modules. This function can heavily modify the OS/files/etc.. so the return value is very important. Returns: True in error : abortPlans function should be called False otherwise : everything is OK """ out.header('Executing plans %r\n' % (update)) # Finding the functions to call is actually done by a 'iterator' like function in the plangraph module while(True): # This function either returns None or a tuple just like generate added to it p = update.plans.getNextTodo() # No more to do? if(not p): break # Explode tuple otherwise func, args = p # We are in a try-except block so if func isn't callable that will catch it try: out.verbose('Calling %s\n' % (func)) # # Call the function from the execution plan # # args may be empty, but we don't want to pass in a tuple if we don't need to # so this below explodes the args so if @args is (), then what is passed is @update skipme = func(*((update, ) + args)) except Exception as e: out.exception(e, True) #, plans=str(update.plans)) # Removed because breaks new out.exception call update.responses.append({'exception': str(e), 'traceback': traceback.format_exc()}) update.failure = str(e) return True # The functions we call here can return other functions, if they do these are functions that should # be skipped later on (for instance a set* function discovering it didn't change anything, later on # we shouldn't call the corresponding reload function) if(skipme): # These functions can return individual functions to skip, or a list of multiple functions if (not isinstance(skipme, list)): skipme = [skipme] for skip in skipme: out.warn('Identified a skipped function: %r\n' % (skip)) update.plans.registerSkip(skip) # Now we are done return False
def generatePlans(update): """ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute. Returns: True: abort the plan generation process """ out.verbose("%r\n" % (update)) # If this chute is new (no old version) if update.old is None: out.verbose("new chute\n") # If it's a stop, start, delete, or restart command go ahead and fail right now since we don't have a record of it if update.updateType in ["stop", "start", "delete", "restart"]: update.failure = "No chute found with id: " + update.name return True # If we are now running then everything has to be setup for the first time if update.new.state == chute.STATE_RUNNING: update.plans.addPlans(plangraph.STATE_CALL_START, (virt.startChute,)) # Check if the state is invalid, we should return bad things in this case (don't do anything) elif update.new.state == chute.STATE_INVALID: if settings.DEBUG_MODE: update.responses.append("Chute state is invalid") return True # Not a new chute else: if update.updateType == "start": if update.old.state == chute.STATE_RUNNING: update.failure = update.name + " already running." return True update.plans.addPlans(plangraph.STATE_CALL_START, (virt.restartChute,)) elif update.updateType == "restart": update.plans.addPlans(plangraph.STATE_CALL_START, (virt.restartChute,)) elif update.updateType == "create": update.failure = update.name + " already exists on this device." return True elif update.new.state == chute.STATE_STOPPED: if update.updateType == "delete": update.plans.addPlans(plangraph.STATE_CALL_STOP, (virt.removeChute,)) if update.updateType == "stop": if update.old.state == chute.STATE_STOPPED: update.failure = update.name + " already stopped." return True update.plans.addPlans(plangraph.STATE_CALL_STOP, (virt.stopChute,)) return None
def delConfig(self, config, options): """Finds a match to the config input and removes it from the internal config data structure.""" config = stringify(config) options = stringify(options) # Search through the config array for matches for i, e in enumerate(self.config): c, o = e if(c == config and o == options): break else: # Getting here means we didn't break so no match out.verbose('No match to delete, config: %r\n' % (config)) return del(self.config[i])
def generatePlans(update): """ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute. Returns: True: abort the plan generation process """ out.verbose("%r\n" % (update)) #print any warnings from previous update if they exist if hasattr(update, 'pkg') and update.old != None and update.old.warning != None: update.pkg.request.write(update.old.warning + '\n') # TODO: Create a directory for the chute for us to hold onto things (dockerfile, OS config stuff) return None
def wrapper(theSelf, request, *args, **kwargs): tictoc = 0 # theSelf.perf.tic() ip = '0.0.0.0' # TODO getIP(request) out.verbose('HTTP request from IP %s\n' % (ip)) request.setHeader('Access-Control-Allow-Origin', settings.PDFCD_HEADER_VALUE) apiPackage = APIPackage(request) # Extract required arguments if(requiredArgs or optionalArgs): body = str2json(request.content.read()) if(requiredArgs): required = explode(body, *requiredArgs) for idx, arg in enumerate(requiredArgs): # Check if required arg exist if(required[idx] is None): return theSelf.rest.failprocess(ip, request, (ip, theSelf.rest.clientFailures), "Malformed Body: %s", (tictoc, None), pdapi.ERR_BADPARAM) # If exist put it into the apiPackage apiPackage.inputArgs[arg] = required[idx] # Extract optional arguments if(optionalArgs): optional = explode(body, *optionalArgs) for idx, arg in enumerate(optionalArgs): if(optional[idx]): apiPackage.inputArgs[arg] = optional[idx] ####################################################################################### # Make the real function call ####################################################################################### func(theSelf, apiPackage, *args, **kwargs) # NOT_DONE_YET if(apiPackage.result is None): return NOT_DONE_YET # SUCCESS elif(apiPackage.result is True): theSelf.rest.postprocess(request, failureKey, failureDict, (tictoc, ip, devid)) return apiPackage.returnVal # FAILURE else: errMsg = apiPackage.errMsg errType = apiPackage.errType if(apiPackage.countFailure): return theSelf.rest.failprocess(ip, request, (failureKey, failureDict), errMsg, (tictoc, devid), errType) else: return theSelf.rest.failprocess(ip, request, None, errMsg, (tictoc, devid), errType)
def preprocess(self, request, checkThresh, tictoc): """ Check if failure attempts for the user name has met the threshold. Arguments: request : checkThresh : If None, no checking. Tuple of arguments for checking thresholds ip: IP of client in string format token: sessionToken if found, or None username: username if signin, or None failureDict: the dict for failure history ticktoc: If none, do not track the usage. The start time of the API call Return: str: if threshold is met None: if ok """ if(checkThresh): ip, token, key, failureDict = checkThresh # Check if IP is in whitelist ipaddr = apiutils.unpackIPAddr(ip) for ipnet in self.WHITELIST_IP: net = apiutils.unpackIPAddrWithSlash(ipnet) if(apiutils.addressInNetwork(ipaddr, net)): out.verbose('Request from white list: %s\n' % (ip)) return None if(key in failureDict): if(failureDict[key].attempts >= settings.DBAPI_FAILURE_THRESH): out.err('Threshold met: %s %s!\n' % (ip, key)) if(tictoc is None): usage = None else: usage = (tictoc, None) self.failprocess(ip, request, (ip, failureDict), None, usage, pdapi.getResponse(pdapi.ERR_THRESHOLD)) duration = 0 # self.perf.toc(tictoc) # Log the info of this call # TODO self.usageTracker.addTrackInfo(ip, 'Null', request.path, self.usageTracker.FAIL_THRESH, duration, request.content.getvalue()) return "Threshold Met!" # Otherwise everything is ok return None
def execute(self): try: proc = subprocess.Popen(self.command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.pid = proc.pid for line in proc.stdout: out.verbose("{}: {}".format(self.command[0], line)) for line in proc.stderr: out.verbose("{}: {}".format(self.command[0], line)) self.result = proc.wait() out.info('Command "{}" returned {}\n'.format( " ".join(self.command), self.result)) except Exception as e: out.info('Command "{}" raised exception {}\n'.format( " ".join(self.command), e)) self.result = e if self.parent is not None: self.parent.executed.append(self) return (self.result == 0)
def oscall(cmd, get=False): """ This function performs a OS subprocess call. All output is thrown away unless an error has occured or if @get is True Arguments: @cmd: the string command to run [get] : True means return (stdout, stderr) Returns: None if not @get and no error (stdout, retcode, stderr) if @get or yes error """ # Since we are already in a deferred chain, use subprocess to block and make the call to mount right HERE AND NOW proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, errors = proc.communicate() if(proc.returncode or get): return (output, proc.returncode, errors) else: if(output and output != ""): out.verbose('"%s" stdout: "%s"\n' % (cmd, output.rstrip())) if(errors and errors != ""): out.verbose('"%s" stderr: "%s"\n' % (cmd, errors.rstrip())) return None