def test_type_success(self): test = "hello world" ensure_type( "test", test, str, )
def from_json(cls, string): """ Takes a JSON encoded string and build a `Script`. Parameters ---------- string: str JSON encoded string. Returns ------- Script: Which was paresed from the JSON encoded string. Raises ------ TypeError: If programs and filesystems have the wrong type. """ data = json.loads(string) ensure_type("programs", data["programs"], list) ensure_type("filesystems", data["filesystems"], list) ensure_type_array("programs", data["programs"], dict) ensure_type_array("filesystems", data["filesystems"], dict) return cls( data["name"], [ScriptEntryProgram(**program) for program in data["programs"]], [ScriptEntryFilesystem(**file) for file in data["filesystems"]], )
def prog_log_disable(program): """ This function disables the log transfer for a `ProgramModel` by sending a command to the slave. If the slave is offline an error will be returned. Parameters ---------- program: ProgramModel A valid `ProgramModel`. Raises ------ SlaveOfflineError TypeError: If `program` is not an `ProgramModel` """ ensure_type("program", program, ProgramModel) LOGGER.info( "Disabling logging for program %s on slave %s", program.name, program.slave.name, ) if not program.slave.is_online: raise SlaveOfflineError('', '', 'log_disable', program.slave.name) notify_slave( Command( method="disable_logging", target_uuid=program.programstatus.command_uuid, ), program.slave.id, )
def test_type_multi(self): test = "hello world" ensure_type( "test", test, int, str, )
def notify_slave(command, slave_id): """ Sending the given `message` to the notification channel. Indicating that the message is an error message. Parameters ---------- message: JSON object This message is send to the web interface with an Status.err() wrapped around. """ ensure_type("command", command, Command) Group('client_' + str(slave_id)).send({'text': command.to_json()})
def filesystem_type_check( source_path, source_type, destination_path, destination_type, backup_ending, ): """ Check the types of the shared input of filesystem_move and filesystem_restore. """ uty.ensure_type("source_path", source_path, str) uty.ensure_type("destination_path", destination_path, str) uty.ensure_type("backup_ending", backup_ending, str) uty.ensure_type("PATH_TYPE_SET", PATH_TYPE_SET, list) if not source_type in PATH_TYPE_SET: raise ValueError( "The source_type has to be one of {}".format(PATH_TYPE_SET)) if not destination_type in PATH_TYPE_SET: raise ValueError( "The destination_type has to be one of {}".format(PATH_TYPE_SET)) source_path = up.remove_trailing_path_seperator(source_path) destination_path = up.remove_trailing_path_seperator(destination_path) source_path = os.path.abspath(source_path) destination_path = os.path.abspath(destination_path) if not os.path.exists(source_path): raise FileNotFoundError( errno.ENOENT, os.strerror(errno.ENOENT), source_path, ) # check if source is dir or file (based on source path) if source_type == 'dir': if not os.path.isdir(source_path): raise ValueError( "The source path `{}` is not a directory.".format(source_path)) elif source_type == 'file': if not os.path.isfile(source_path): raise ValueError( "The source path `{}` is not a file.".format(source_path)) # extract source name from path source_file = os.path.basename(source_path) # destination is a directory if destination_type == 'dir': destination_path = os.path.join(destination_path, source_file) return ( source_path, source_type, destination_path, destination_type, backup_ending, source_file, )
def assertStatusRegex(self, regex_status, status_object): """ Asserts that status_object.payload matches the regex_status.payload and that both have the same status type. regex_status.payload can be either an FsimError or an regex expression (as a string). Exceptions ---------- TypeException: if regex_status or status_object are not Status objects or if the payload is not a string. """ ensure_type("regex_status", regex_status, Status) ensure_type("status_object", status_object, Status) ensure_type("status_object.payload", status_object.payload, str) ensure_type( "regex_status.payload", status_object.payload, str, FsimError, FsimError.__class__, ) if isinstance(regex_status.payload, FsimError) or isinstance( regex_status.payload, FsimError.__class__): regex_string = regex_status.payload.regex_string() elif isinstance(regex_status.payload, str): regex_string = regex_status.payload self.assertEqual(regex_status.status, status_object.status) self.assertRegex(status_object.payload, regex_string)
def filesystem_restore( source_path, source_type, destination_path, destination_type, backup_ending, hash_value, ): """ Restores a previously moved object. Arguments --------- source_path: path to the source source_type: Type of the source (a directory -> 'dir' or a file -> 'file') destination_path: path to the destination destination_type: Type of the destination (place it in a directory -> 'dir' or replace it -> 'file') backup_ending: the file ending for backup files """ uty.ensure_type("hash_value", hash_value, str) ( source_path, source_type, destination_path, destination_type, backup_ending, _, ) = sh.filesystem_type_check( source_path, source_type, destination_path, destination_type, backup_ending, ) backup_path = destination_path + backup_ending if os.path.exists(destination_path): if source_type == 'dir': shutil.rmtree(destination_path) elif source_type == 'file': os.remove(destination_path) if os.path.exists(backup_path): os.rename(backup_path, destination_path) return None
def fs_restore(fs): """ This functions restores a given `fs` by sending a command to the slave to restore the original state. If the slave is offline an error will be returned. Parameters ---------- fs: FilesystemModel A valid `FilesystemModel`. Raises ------ SlaveOfflineError FilesystemNotMovedError TypeError: If `fs` is not an `FilesystemModel` """ ensure_type("fs", fs, FilesystemModel) slave = fs.slave if slave.is_online: if not fs.is_moved: raise FilesystemNotMovedError( str(fs.name), str(fs.slave.name), ) cmd = Command( method="filesystem_restore", source_path=fs.source_path, source_type=fs.source_type, destination_path=fs.destination_path, destination_type=fs.destination_type, backup_ending=FILE_BACKUP_ENDING, hash_value=fs.hash_value, ) # send command to the client notify_slave(cmd, slave.id) fs.command_uuid = cmd.uuid fs.save() else: raise SlaveOfflineError( str(fs.name), "filesystem", str(fs.slave.name), "restore", )
def script_deep_copy(script): """ This function creates a copy of a `ScriptModel` with all `ScriptGraphFiles` and `ScriptGraphPrograms`. The result `ScriptModle` has the same name but with an suffix '_copy'. If the `ScriptModel` with the suffix already exists then a number is appended to the name. Parameters ---------- slave: ScriptModel A valid `ScriptModel`. Returns ------- copy: ScriptModel The copy of the `script` with a new name. Raises ------ TypeError: If `script` is not an `ScriptModel` """ ensure_type("script", script, ScriptModel) i = 0 copy = None while not copy: if i is 0: name = script.name + '_copy' else: name = script.name + '_copy_' + str(i) if ScriptModel.objects.filter(name=name).exists(): i = i + 1 else: copy = ScriptModel(name=name) copy.save() for file_entry in SGF.objects.filter(script_id=script.id): SGF(script=copy, index=file_entry.index, filesystem=file_entry.filesystem).save() for program_entry in SGP.objects.filter(script_id=script.id): SGP(script=copy, index=program_entry.index, program=program_entry.program).save() return copy
def remove_trailing_path_seperator(path): """ If the last character is a path seperator, then it will be removed. Arguments ---------- path: string Returns ------- string """ ensure_type("path", path, str) if path and (path[-1] == '\\' or path[-1] == '/'): return path[:-1] else: return path
def prog_stop(prog): """ This function stops a `prog` by sending a command to the slave. The program can only be stoped if the program is currently running. If the slave is offline an error will be returned. Parameters ---------- prog: ProgramModel A valid `ProgramModel`. Exception ------- SlaveOfflineError ProgramNotRunningError TypeError: If `prog` is not an `ProgramModel` """ ensure_type("prog", prog, ProgramModel) if prog.slave.is_online: if not prog.is_running: raise ProgramNotRunningError(str(prog.name), str(prog.slave.name)) LOGGER.info( "Stoping program %s on slave %s", prog.name, prog.slave.name, ) notify_slave( Command( method="execute", uuid=prog.programstatus.command_uuid, ), prog.slave.id, ) else: raise SlaveOfflineError( str(prog.name), "program", str(prog.slave.name), "stop", )
def slave_wake_on_lan(slave): """ This functions starts a `slave` by sending a magic (Wake-On-Lan package) to the `slave`. Parameters ---------- slave: SlaveModel A valid `SlaveModel`. Raises ------ TypeError: If `slave` is not an `SlaveModel` """ ensure_type("slave", slave, SlaveModel) send_magic_packet(slave.mac_address) notify({"message": "Send start command to client `{}`".format(slave.name)})
def fs_delete(fs): """ This functions deletes a `fs` only if `fs` is not moved. Parameters ---------- fs: FilesystemModel A valid `FilesystemModel`. Raises ------ FilesystemDeleteError TypeError: If `fs` is not an `FilesystemModel` """ ensure_type("fs", fs, FilesystemModel) if not fs.is_moved: fs.delete() else: raise FilesystemDeleteError(str(fs.name), str(fs.slave.name))
def convert_str_to_bool(string): """ Converts a string into a boolean by checking common patterns. If no pattern is matching the default (False) is returned. Common string patterns are for the boolean true are on of ('yes', 'true', '1', 't', 'y'). Parameters ---------- string: str The string which will be converted. Returns ------- bool: If one of the patterns was found in the string. Raises ------ TypeError: If string is not a str instance. """ ensure_type("string", string, str) return string.lower() in ('yes', 'true', '1', 't', 'y')
def prog_log_get(program): """ This function is asking for a log for a `program` by sending a command to the slave. If the slave is offline an error will be returned. Parameters ---------- program: ProgramModel A valid `ProgramModel`. Raises ------ SlaveOfflineError LogNotExistError TypeError: If `program` is not an `ProgramModel` """ ensure_type("program", program, ProgramModel) LOGGER.info( "Requesting log for program %s on slave %s", program.name, program.slave.name, ) if not program.slave.is_online: raise SlaveOfflineError('', '', 'get_log', program.slave.name) if not (program.is_executed or program.is_running): raise LogNotExistError(program.id) notify_slave( Command( method="get_log", target_uuid=program.programstatus.command_uuid, ), program.slave.id, )
def from_identifier(identifier, is_string): """ Returns an slave based on the given `identifier` which can be an index or a name. Parameters ---------- identifier: str Which is a `name` or `index` form the `Slave` model. is_string: bool If the `identifier` should be interpreted as a `name` or ` index`. Returns ------- Slave: If the type was correct and the slave exist. Raises ------ Slave.DoesNotExist: If no slave with the given `identifier` exist. TypeError: If `identifier` and `is_string` have not the correct type. IdentifierError: If `is_string` is False and the `identifier` can not be transformed into an int. """ ensure_type("identifier", identifier, str) ensure_type("is_string", is_string, bool) if is_string: return Slave.objects.get(name=identifier) else: try: return Slave.objects.get(id=int(identifier)) except ValueError: raise IdentifierError("slave", "int", identifier)
def __init__(self, index, filesystem, slave): ensure_type("index", index, int) if index < 0: raise PositiveNumberError(index, "index") self.index = index ensure_type("filesystem", filesystem, str, int) self.filesystem = filesystem ensure_type("slavesystem", slave, str, int) self.slave = slave
def __init__(self, index, program, slave): ensure_type("index", index, int) if index < 0: raise PositiveNumberError(index, "index") self.index = index ensure_type("program", program, str, int) self.program = program ensure_type("slave", slave, str, int) self.slave = slave
def __init__(self, name, programs, filesystems): ensure_type("programs", programs, list) ensure_type_array("programs", programs, ScriptEntryProgram) self.programs = programs ensure_type("filesystems", filesystems, list) ensure_type_array("filesystem", filesystems, ScriptEntryFilesystem) self.filesystems = filesystems ensure_type("name", name, str) self.name = name
def __init__(self, error, identifier): ensure_type("error", error, frontend.models.Program.DoesNotExist) super().__init__("program", identifier)
def __init__(self, error, identifier): ensure_type("error", error, frontend.models.Filesystem.DoesNotExist) super().__init__("filesystem", identifier)
def fs_move(fs): """ This functions sends a command to slave to move the given filesystem. If any filesystem is at the same place it will be restored and the then `fs` will be moved. If the slave is offline an error will be returned. Parameters ---------- fs: FilesystemModel A valid `FilesystemModel`. Raises ------ SlaveOfflineError FilesystemMovedError TypeError: If `fs` is not an `FilesystemModel` """ ensure_type("fs", fs, FilesystemModel) slave = fs.slave if slave.is_online: if fs.is_moved: raise FilesystemMovedError( str(fs.name), str(fs.slave.name), ) if fs.destination_type == 'file': lookup_file_name = os.path.basename(fs.source_path) lookup_file = fs.destination_path (lookup_dir, _) = os.path.split(fs.destination_path) elif fs.destination_type == 'dir': lookup_file_name = os.path.basename(fs.source_path) lookup_file = os.path.join(fs.destination_path, lookup_file_name) lookup_dir = fs.destination_path query = FilesystemModel.objects.filter( ~Q(hash_value__exact='') & ~Q(id=fs.id) & ((Q(destination_path=lookup_file) & Q(destination_type='file')) | (Q(destination_path=lookup_dir) & Q(destination_type='dir') & (Q(source_path__endswith='/' + lookup_file_name) | Q(source_path__endswith='\\' + lookup_file_name))))) if query: filesystem_replace = query.get() first = Command( method="filesystem_restore", source_path=filesystem_replace.source_path, source_type=filesystem_replace.source_type, destination_path=filesystem_replace.destination_path, destination_type=filesystem_replace.destination_type, backup_ending=FILE_BACKUP_ENDING, hash_value=filesystem_replace.hash_value, ) second = Command( method="filesystem_move", source_path=fs.source_path, source_type=fs.source_type, destination_path=fs.destination_path, destination_type=fs.destination_type, backup_ending=FILE_BACKUP_ENDING, ) cmd = Command( method="chain_execution", commands=[dict(first), dict(second)], ) filesystem_replace.command_uuid = first.uuid filesystem_replace.save() fs.command_uuid = second.uuid fs.save() else: cmd = Command( method="filesystem_move", source_path=fs.source_path, source_type=fs.source_type, destination_path=fs.destination_path, destination_type=fs.destination_type, backup_ending=FILE_BACKUP_ENDING, ) fs.command_uuid = cmd.uuid fs.save() # send command to the client notify_slave(cmd, slave.id) else: raise SlaveOfflineError( str(fs.name), "filesystem", str(fs.slave.name), "move", )
def __init__(self, error, identifier): ensure_type("error", error, frontend.models.Script.DoesNotExist) super().__init__("script", identifier)
def prog_start(prog): """ This functions starts a `prog` by sending a command to the slave. The program can only be started if the program is currently not running. If the slave is offline an error will be returned. Parameters ---------- prog: ProgramModel A valid `ProgramModel`. Raises ------ SlaveOfflineError ProgramRunningError TypeError: If `prog` is not an `ProgramModel` """ ensure_type("prog", prog, ProgramModel) if prog.slave.is_online: if prog.is_running: raise ProgramRunningError(str(prog.name), str(prog.slave.name)) uuid = uuid4().hex cmd = Command( uuid=uuid, # for the command pid=prog.id, own_uuid=uuid, # for the function that gets executed method="execute", path=prog.path, arguments=[prog.arguments], ) LOGGER.info( "Starting program %s on slave %s", prog.name, prog.slave.name, ) # send command to the client notify_slave(cmd, prog.slave.id) # tell webinterface that the program has started notify({ 'program_status': 'started', 'pid': prog.id, }) # create status entry ProgramStatusModel(program=prog, command_uuid=cmd.uuid, start_time=now()).save() if prog.start_time > 0: LOGGER.debug( 'started timeout on %s, for %d seconds', prog.name, prog.start_time, ) LOGGER.debug(type(prog.start_time)) FSIM_CURRENT_SCHEDULER.spawn( prog.start_time, timer_timeout_program, prog.id, ) elif prog.start_time == 0: timer_timeout_program(prog.id) else: raise SlaveOfflineError( str(prog.name), "program", str(prog.slave.name), "start", )