Example #1
0
            def process_dict_input(dictionary):

                # vars.
                expect = list(dictionary.keys())
                send = list(dictionary.values())

                # expect .
                if log_level >= 8:
                    print(f"Expecting one of the following inputs: {expect}.")
                response = spawn.expect(expect=expect,
                                        send=send,
                                        timeout=timeout)
                if not response.success:
                    if "None of the specified inputs were expected." in response.error:
                        if optional:
                            return Response.error(
                                f"Unable to find the expected input but still success since it is optional."
                            )
                        else:
                            return Response.error(
                                f"Specified input [{Array(expect).string(joiner=', ')}] was not expected."
                            )
                    else:
                        return response
                if log_level >= 8:
                    print("Send response message:", response.message)

                # success.
                return Response.success("Success.")
Example #2
0
	def send_crash(self, 
		# all optional.
		# option 1: the success message.
		message=None, # (1)
		args={}, # (2)
		# option 2: the error message.
		error=None,
		# option 3: the response object.
		response=None, 
		# save the message/error/response.
		save=False,
		# the active log level (int) (leave None to use self.log_level).
		log_level=None,
		# the required log level for when to print to console (leave None to use Response.log_level ; default: 0).
		required_log_level=Response.log_level,
	):
		if log_level == None: log_level = self.log_level
		if isinstance(message, (str,String)):
			self.__response__ = Response.success(message, args, log_level=-1, save=False)
			msg = message
		elif isinstance(error, (str,String)):
			self.__response__ = Response.error(error, log_level=-1, save=False)
			msg = error
		elif isinstance(response, ResponseObject):
			self.__response__ = response
			if response["success"]:
				msg = response["message"]
			else:
				msg = response["error"]
		else:
			raise Exceptions.InvalidUsage("Define one of the following parameters: [message:str, error:str, response:ResponseObject].")
		self.__status__ = "crashed"
		if log_level >= required_log_level or save:
			Response.log(response=self.__response__, save=save, log_level=log_level, required_log_level=required_log_level)
		return self.__response__
Example #3
0
 def crashed(self):
     response = self.read(wait=False)
     if not response.success: return response
     if self.exit_status not in [0, None]:
         return Response.error(
             f"{self.response_str} returned exit status: [{self.exit_status}] (output: {self.read(wait=False, __safe__=True).output})."
         )
     return Response.success(f"{self.response_str} is not crashed.")
Example #4
0
	def safe_start(self, timeout=120, sleeptime=1):
		self.log(f"Stopping thread {self.id}.")
		self.start()
		for i in range(int(timeout/sleeptime)):
			if self.running: break
			time.sleep(sleeptime)
		if not self.running: 
			return Response.error(f"Unable to start thread {self}.", log_level=self.log_level, required_log_level=0)
		return Response.success(f"Successfully started thread {self.id}.", log_level=self.log_level, required_log_level=0)
Example #5
0
 def start(self):
     try:
         self.child = pexpect.spawn(self.command)
     except Exception as e:
         return Response.error(
             f"Failed to spawn {self.response_str}, error: {e}.")
     # check exit status.
     if self.child.exitstatus not in [0, None]:
         return OutputObject(
             error=
             f"{self.response_str} returned exit status: [{spawn.child.exitstatus}] (output: {self.read(wait=False, __safe__=True).output})."
         )
     self.__output__ = ""
     return Response.success(f"Successfully spawned {self.response_str}.")
Example #6
0
    def kill(self):

        # handle output.
        killed = None
        try:
            #if self.async_:
            #	g = yield from self.child.terminate(force=True, async_=True)
            #	killed = next(x)
            #else:
            killed = self.child.terminate(force=True)
        except Exception as e:
            return Response.error(
                f"Failed to kill process [{self.command}], error: {e}.")
        if killed == None:
            return Response.error(
                f"Failed to kill process [{self.command}] (#452983).")
        if not killed:
            return Response.error(f"Unable to kill process [{self.command}].")
        else:
            return Response.success(
                f"Successfully killed process [{self.command}].")
Example #7
0
	def safe_stop(self, timeout=120, sleeptime=1):
		self.log(f"Stopping thread {self.id}.")
		self.send_stop()
		for i in range(int(timeout/sleeptime)):
			if self.stopped: break
			time.sleep(sleeptime)
		if not self.stopped: 
			return Response.error(f"Unable to stop thread {self}.")
		found = False
		try:
			response = self.stop()
			found = True
		except AttributeError: response = None
		if not found:
			try:
				response = self.__stop__()
				found = True
			except AttributeError: response = None
		if isinstance(response, ResponseObject) and not response.success:
			return response
		return Response.success(f"Successfully stopped thread {self.id}.", required_log_level=0)
Example #8
0
	def log(self, 
		# option 1:
		# the message (#1 param).
		message=None,
		# option 2:
		# the error.
		error=None,
		# option 3:
		# the response dict (leave message None to use).
		response={},
		# print the response as json.
		json=JSON,
		# optionals:
		# the active log level (leave None to use self.log_level).
		log_level=None,
		# the required log level for when printed to console.
		required_log_level=0, 
		# save to log file.
		save=False,
		# save errors always (for options 2 & 3 only).
		save_errors=None,
		# the log mode (leave None for default).
		mode=None,
	):
		if log_level == None: log_level = self.log_level
		return Response.log( 
			# option 1:
			# the message (#1 param).
			message=message,
			# option 2:
			# the error.
			error=error,
			# option 3:
			# the response dict (leave message None to use).
			response=response,
			# print the response as json.
			json=json,
			# optionals:
			# the active log level.
			log_level=log_level,
			# the required log level for when printed to console (leave None to use self.log_level).
			required_log_level=required_log_level, 
			# save to log file.
			save=save,
			# save errors always (for options 2 & 3 only).
			save_errors=save_errors,
			# the log mode (leave None for default).
			mode=mode,
		)
Example #9
0
    def expect(
        self,
        # the expected data parameter (#1).
        #	str instantce: expect a single identifier.
        #	list instance: expect one of the provided identifiers & return the found one if success.
        expect=["Password*"],
        # the optional data to send (#2).
        #	none instance: do not send anything.
        #	str instance: the data to send.
        #	list/tuple instance: send value of index from expected expect (required expect to be a list, Array & the indexes of [expect, send] be match).
        send=None,
        # the timeout (float).
        timeout=1.0,
    ):
        # check none timeout.
        if timeout == None: timeout = 1.0

        # single expect.
        if isinstance(expect, str):
            if isinstance(send, (list, Array)):
                raise Exceptions.InvalidUsage(
                    f"{self.__traceback__(function='expect', parameter='send')}: parameter [send] requires to be be a [str, String] when parameter [expect] is a [{expect.__class__.__name__}], not [{send.__class__.__name__}]."
                )
            """ add to lines to output (before) (adds nothing when empty) (do not use self.expecting before adding the output). """
            response = self.read(wait=False)
            if not response.success: return response
            """ check expect & send if provided. """
            c = 1
            try:
                #if self.async_:
                #	g = yield from self.child.expect(expect, timeout=timeout, async_=True)
                #	r = next(g)
                #else:
                r = self.child.expect(expect, timeout=timeout)
                if not isinstance(r, (int, Integer, float)):
                    return Response.error(
                        f"Expected [{expect}] is not the child's expected input (#873465)."
                    )
                c = 2
                if self.log_level >= 8: print(f"Found expected: {expect}")
                if send != None:
                    if self.log_level >= 8:
                        print(f"Attempting to send: {send}")
                    #if self.async_:
                    #	g = yield from self.child.sendline(str(send), async_=True)
                    #	r = next(g)
                    #else:
                    r = self.child.sendline(str(send))
                    self.__secrets__.append(str(send))
                    if self.log_level >= 8:
                        print(f"Succesfully sended: {send}")
            except pexpect.exceptions.TIMEOUT:
                if c == 1:
                    return Response.error(
                        f"Expected [{expect}] is not the child's expected input, error: Timeout (during epxecting)."
                    )
                else:
                    return Response.error(
                        f"Failed to send expected [{expect}], error: Timeout (during sending input)."
                    )
            except pexpect.exceptions.EOF:
                if c == 1:
                    return Response.error(
                        f"Expected [{expect}] is not the child's expected input, error: End of file (during epxecting)."
                    )
                else:
                    return Response.error(
                        f"Failed to send expected [{expect}], error: End of file (during sending input)."
                    )
            except Exception as e:
                if c == 1:
                    return Response.error(
                        f"Expected [{expect}] is not the child's expected input, error: {e}."
                    )
                else:
                    return Response.error(
                        f"Failed to send expected [{expect}], error: {e}.")
            """ add to lines to output (after) (adds nothing when empty) (do not use self.expecting before adding the output). """
            response = self.read(wait=False)
            if not response.success: return response

            # handler.
            if send != None:
                return Response.success(
                    f"Successfully send expected input ({expect}).")
            else:
                return Response.success(
                    f"Successfully retrieved expected input ({expect}).")

        # list expect.
        elif isinstance(expect, (list, Array)):
            index = 0
            for _expect_ in expect:
                if isinstance(send, (list, Array)):
                    try:
                        _send_ = str(send[index])
                    except:
                        raise Exceptions.InvalidUsage(
                            f"{self.__traceback__(function='expect', parameter='send')}: parameter [send] and parameter [expect] do not have the same indexes."
                        )
                else:
                    _send_ = str(send)
                if self.log_level >= 8:
                    print(f"Checking optional expect: {_expect_}")
                response = self.expect(expect=_expect_,
                                       timeout=timeout,
                                       send=_send_)
                if not response.success and "is not the child's expected input" not in response.error:
                    return response
                elif response.success:
                    return Response.success(
                        f"Successfully {Boolean(send).string(true='send', false='retrieved')} the expected input(s).",
                        {
                            "expected": _expect_,
                            "index": index,
                        })
                index += 1
            return Response.error(f"None of the specified input was expected.")

        # invalid usage.
        else:
            raise Exceptions.InvalidUsage(
                f"{self.__traceback__(function='expect', parameter='expect')}: parameter [expect] requires to be be a [Dictionary], not [{config.__class__.__name__}]."
            )
Example #10
0
def execute(
    # Notes:
    #   returns a syst3m.console.OutputObject object (very similair to ResponseObject).
    #
    # Mode:
    #   option 1:
    #     the command in str format, the command is saved to a script & then executed).
    command="ls .",
    #     joiner for when command is in list format.
    joiner=" ",
    #   option 2: the path to script.
    path=None,
    #
    # Executement:
    #   the executable.
    executable="sh",
    #   the arguments passed to the (saved) script.
    arguments=[],
    #
    # Options:
    #   asynchronous process.
    async_=False,
    #	await asynchronous child (sync process always awaits).
    wait=False,
    #	kill process when finished (async that is not awaited is never killed).
    kill=True,
    #   the subprocess shell parameter.
    shell=False,
    #   serialize output to dict (expect literal dictionary / json output).
    serialize=False,
    #
    # Input (sync only):
    #   send input to the command.
    #	  undefined: send no input & automatically await the process since input is always sync.
    #	  dict instance: selects "and" mode ; send expected inputs and their value & return error when one of them is missing.
    #	  list[dict] instance: send all dictionaries in the list (default dict behaviour so one of the keys in each dict is expected).
    input=None,
    #   the input timeout (float) (list with floats by index from input)
    timeout=1.0,
    #   do not throw an error when the input is missing or not expected when optional is disabled (bool).
    optional=False,
    #
    # Logging.
    #   the log level.
    log_level=Defaults.options.log_level,
    #
    # System functions.
    #   add additional attributes to the spawn object.
    __spawn_attributes__={},
    #
):

    # checks,
    if input != None and not isinstance(input,
                                        (dict, Dictionary, list, Array)):
        raise Exceptions.InvalidUsage(
            f"<Code.execute>: Parameter [input] requires to be be a [dict, Dictionary, list, Array], not [{iput.__class__.__name__}]."
        )

    # vars.
    delete = False
    if path == None:
        delete = True
        path = f"/tmp/tmp_script_{String('').generate()}"
        if isinstance(command, list):
            command = Array(array=command).string(joiner=joiner)
        Files.save(path, command)
        response_str = f"command ({command})"
    else:
        response_str = f"script ({path})"

    # execute with input.
    #if isinstance(input, (dict, Dictionary, list, Array)):

    # checks.
    #if async_:
    #	raise Exceptions.InvalidUsage(f"<Code.execute>: Parameters [input] & [async] are not compatible, select either one.")

    # spawn.
    l = []
    for i in arguments:
        l.append(f'"{i}"')
    arguments = Array(l).string(joiner=' ')
    if log_level >= 8: print(f"Spawn: [ $ {executable} {path} {arguments}]", )
    spawn = Spawn(
        command=f"{executable} {path} {arguments}",
        #async_=async_, # does not work.
        response_str=response_str,
        log_level=log_level,
        attributes=__spawn_attributes__,
    )
    spawn.echo = False
    if isinstance(timeout, (int, float, Integer)):
        spawn.timeout = int(timeout)

    # start.
    response = spawn.start()
    if not response.success:
        return OutputObject(
            error=f"Failed to start {response_str}, error: {response.error}",
            log_level=log_level)

    # check crashed
    response = spawn.crashed()
    if not response.success:
        return OutputObject(error=response.error, log_level=log_level)

        # has already exited.
    elif spawn.exit_status in [0]:

        # get output.
        response = spawn.wait(timeout=1.0)
        if not response.success:
            return OutputObject(error=response.error,
                                log_level=log_level)  # exit status.
        output = response.output

        #

    # proceed if already finished.
    elif spawn.exit_status not in [0]:

        # await.
        for i in range(10):
            if spawn.running: break
            time.sleep(1)
        if not spawn.running:
            return OutputObject(error=f"Unable to start {response_str}.",
                                log_level=log_level)

        # str input.
        if isinstance(input, (list, Array)):
            if len(input) > 0:
                str_input = Array(list(input[0].keys())).string(joiner=", ")
            else:
                str_input = Array(input).string(joiner=", ")
        elif isinstance(input, (dict, Dictionary)):
            str_input = Array(list(input.keys())).string(joiner=", ")
        else:
            str_input = f"[{input}]"

        # send optional input.
        error_end_of_file = None
        if not async_ and isinstance(
                input, (list, Array, dict, Dictionary)) and len(input) > 0:

            # expect one of the keys in the dictionary.
            def process_dict_input(dictionary):

                # vars.
                expect = list(dictionary.keys())
                send = list(dictionary.values())

                # expect .
                if log_level >= 8:
                    print(f"Expecting one of the following inputs: {expect}.")
                response = spawn.expect(expect=expect,
                                        send=send,
                                        timeout=timeout)
                if not response.success:
                    if "None of the specified inputs were expected." in response.error:
                        if optional:
                            return Response.error(
                                f"Unable to find the expected input but still success since it is optional."
                            )
                        else:
                            return Response.error(
                                f"Specified input [{Array(expect).string(joiner=', ')}] was not expected."
                            )
                    else:
                        return response
                if log_level >= 8:
                    print("Send response message:", response.message)

                # success.
                return Response.success("Success.")

            """ check expecting. """
            expecting = True
            if not spawn.expecting:
                expecting = False
                if not optional:
                    if log_level >= 1:
                        return OutputObject(
                            error=
                            f"Failed to send expected input {str_input} to {response_str}, child is not expecting any input [{spawn.child}].",
                            log_level=log_level)
                    else:
                        return OutputObject(
                            error=
                            f"Failed to send expected input {str_input} to {response_str}, child is not expecting any input.",
                            log_level=log_level)

            # limit not expecting by optional.
            if expecting:

                # send all dicts in the list (list instance).
                error_end_of_file = False
                if isinstance(input, (list, Array)):
                    for _input_ in input:
                        response = process_dict_input(_input_)
                        if not response.success:
                            if "End of file" in response.error:
                                error_end_of_file = True
                            else:
                                # str input.
                                if isinstance(_input_, (list, Array)):
                                    str_input = Array(_input_).string(
                                        joiner=", ")
                                elif isinstance(_input_, (dict, Dictionary)):
                                    str_input = Array(list(
                                        _input_.keys())).string(joiner=", ")
                                else:
                                    str_input = f"[{_input_}]"
                                if optional:
                                    break
                                else:
                                    return OutputObject(
                                        error=
                                        f"Failed to send one of the expected input(s) {str_input}, error: {response.error}",
                                        log_level=log_level)

                # send one of the keys (dict instance).
                elif isinstance(input, (dict, Dictionary)):
                    response = process_dict_input(input)
                    if not response.success:
                        if "End of file" in response.error:
                            error_end_of_file = True
                        elif not optional:
                            return OutputObject(
                                error=
                                f"Failed to send one of the expected input(s) {str_input}, error: {response.error}",
                                log_level=log_level)
                """ check no input left (does not work properly).
				if not error_end_of_file and spawn.expecting:
					try: after = spawn.child.after.decode()
					except : after = spawn.child.after
					return OutputObject(error=f"Failed to execute {response_str}, still expecting: [{after}].", log_level=log_level)
				"""

        # do not get or kill when async.
        output = None
        if not async_:

            # check crashed.
            response = spawn.crashed()
            if not response.success:
                return OutputObject(error=response.error, log_level=log_level)

            # always await sync.
            response = spawn.wait()
            if not response.success:
                return OutputObject(error=response.error, log_level=log_level)
            output = response.output
            if error_end_of_file != None and error_end_of_file:
                if log_level >= 1:
                    return OutputObject(
                        error=
                        f"Failed to send expected input {str_input} to {response_str} (#234343) (output: {output}) (child: {spawn.child}).",
                        log_level=log_level)
                else:
                    return OutputObject(
                        error=
                        f"Failed to send expected input {str_input} to {response_str} (#234343) (output: {output}).",
                        log_level=log_level)

            # check kill.
            if kill and spawn.running:
                if log_level >= 8: print(f"Killing process {response_str}.")
                response = spawn.kill()
                if not response.success:
                    return OutputObject(
                        error=
                        f"Failed to kill {response_str}, error: {response.error}",
                        log_level=log_level)

        # async.
        elif async_:

            # check exit status.
            response = spawn.read(wait=False)
            if not response.success:
                if not response.success:
                    return OutputObject(
                        error=
                        f"Failed to retrieve output from spawn {response_str}, error: {response.error}",
                        log_level=log_level)
            if spawn.child.exitstatus not in [0, None]:
                return OutputObject(
                    error=
                    f"{response_str} returned exit status: [{spawn.child.exitstatus}] (output: {self.read(wait=False, __safe__=True).output}).",
                    log_level=log_level)

            # await async.
            if wait:

                # await.
                response = spawn.wait()
                if not response.success:
                    return OutputObject(error=response.error,
                                        log_level=log_level)  # exit status.
                output = response.output

                if spawn.child.exitstatus not in [0, None]:
                    return OutputObject(
                        error=
                        f"{response_str} returned exit status: [{spawn.child.exitstatus}] (output: {self.read(wait=False, __safe__=True).output}).",
                        log_level=log_level)

                # check kill.
                if kill and spawn.running:
                    if log_level >= 8:
                        print(f"Killing process {response_str}.")
                    response = spawn.kill()
                    if not response.success:
                        return OutputObject(
                            error=
                            f"Failed to kill {response_str}, error: {response.error}",
                            log_level=log_level)

    # handler.
    if delete: Files.delete(path)
    if serialize:
        try:
            response = Response.ResponseObject(json=output)
        except Exception as e:
            if loader != None: loader.stop(success=False)
            return OutputObject(
                error=f"Failed to serialize (output: {output}).",
                log_level=log_level)
        if not response.success:
            return OutputObject(
                error=
                f"Encoutered an error in the serialized response, error: {response.error}",
                log_level=log_level)
    return OutputObject(message=f"Succesfully executed {response_str}.",
                        log_level=log_level,
                        attributes={
                            "output": output,
                            "process": spawn,
                            "pid": spawn.child.pid,
                            "running": spawn.running,
                            "exit_status": spawn.exit_status,
                        })
    """
Example #11
0
 def response(self):
     return Response.response(self.dict())
Example #12
0
    def read(
        self,
        # with await False it reads only the printed output regardless the status & never throws timeout.
        wait=False,
        # the timeout, leave None for no timeout.
        timeout=None,
        # the live boolean (bool) (prints live logs to console when enabled) (leave None to use self.log_level >= 1).
        live=None,
        # system variables.
        #   safe True always a response.output variable upon error the response.output is "".
        __safe__=False,
    ):

        # clean line.
        def clean_line(line):
            if isinstance(line, bytes): line = line.decode()
            if line in [" password:"******"", " ", "  ", "   ", "    "
                    ] and len(line) >= len(strip_last) and line[
                            -len(strip_last):] == strip_last:
                        return line[:-len(strip_last)]
            return line

        def clean_output(output):
            _output_, b = "", output.replace("\r", "").replace("\t",
                                                               "").split("\n")
            c, m = 0, len(b) - 1
            for line in b:
                l = clean_line(line)
                if l not in [None]:
                    if c < m: _output_ += l + "\n"
                    else: _output_ += l
                c += 1
            return _output_

        def log_output(output):
            while True:
                if len(output) >= 1 and output[len(output) - 1] == "\n":
                    output = output[:-1]
                else:
                    break
            print(output)

        # checks.
        if live == None: live = self.log_level >= 1

        # old timeout.
        old = self.child.timeout

        # version 2: reads only the printed lines and stops when the timeout is hit so there is no timeout required.
        output_logs_allowed = True
        if not wait:
            self.child.timeout = 0.25
            output_logs_allowed = False
            output, c = "", 0
            for line in range(1000000000):
                try:
                    #if self.async_:
                    #	g = yield from self.child.readline(line, async_=True)
                    #	output += next(g).decode()
                    #else:
                    new = self.child.readline(line).decode()
                    if new == "":
                        c += 1
                        if c >= 100: break
                    else:
                        output_logs_allowed = True
                        c = 0
                        output += new
                except pexpect.exceptions.TIMEOUT:
                    break
                except pexpect.exceptions.EOF:
                    break
                except Exception as e:
                    if timeout != None: self.child.timeout = old
                    e = str(e)
                    if self.log_level <= 0:
                        e = str(e).split(
                            "\n"
                        )[0]  # strip the full child from the pexpect error message.
                    while True:
                        if len(e) >= 1 and e[len(e) - 1] == ".": e = e[:-1]
                        else: break
                    if "Timeout" in str(e):
                        response = Response.error(
                            f"{e} (most likely the command is still expecting input)."
                        )
                        if __safe__: response.output = ""
                        return response
                    else:
                        response = Response.error(f"{e}.")
                        if __safe__: response.output = ""
                        return response

        # version 1: throws an error when unable to read output if timeout is defined, so it can be used to detect if input is expected.
        else:

            # handle output.
            self.child.timeout = timeout
            try:
                #output = self.child.read().decode()
                output = ""
                #if self.async_:
                #	g = yield from self.child.readlines(async_=True)
                #	lines = next(x)
                #else:
                lines = self.child.readlines()
                if lines == []:
                    output_logs_allowed = False
                else:
                    for i in lines:
                        output += i.decode()
            except Exception as e:
                self.child.timeout = old
                e = str(e)
                if self.log_level <= 0:
                    e = str(e).split(
                        "\n"
                    )[0]  # strip the full child from the pexpect error message.
                while True:
                    if len(e) >= 1 and e[len(e) - 1] == ".": e = e[:-1]
                    else: break
                if "Timeout" in str(e):
                    response = Response.error(
                        f"{e} (most likely the command is still expecting input)."
                    )
                    if __safe__: response.output = ""
                    return response
                else:
                    response = Response.error(f"{e}.")
                    if __safe__: response.output = ""
                    return response

        # clean output.
        output = clean_output(output)
        if output_logs_allowed and live: log_output(output)

        # handler.
        self.child.timeout = old
        self.__output__ += output
        self.__output__ = clean_output(self.__output__)
        return Response.success("Successfully retrieved the child's output.", {
            "output": str(self.__output__),
            "new_output": output,
        })