def connect(self):
        fn_server_public = os.path.expanduser(constants.FN_SERVER_CERT_PUBLIC)
        xt_server_cert = self.config.get_vault_key("xt_server_cert")

        use_public_half = False  # cannot get the public half approach to work

        try:
            # write CERT file JIT
            if use_public_half:
                _, public_half = xt_server_cert.split("END PRIVATE KEY-----\n")
                file_utils.write_text_file(fn_server_public, public_half)
            else:
                file_utils.write_text_file(fn_server_public, xt_server_cert)

            self.conn = rpyc.ssl_connect(self.ip,
                                         port=self.port,
                                         keyfile=None,
                                         certfile=fn_server_public)

            if self.conn:
                # magic step: allows our callback to work correctly!
                # this must always be executed (even if self.conn is already true)
                self.bgsrv = rpyc.BgServingThread(self.conn)
                console.diag("  now running BgServingThread")
        finally:
            # delete the CERT file
            #os.remove(fn_server_public)
            pass

        connected = not (not self.conn)
        return connected
            def set_timer(timeout):
                console.print("set_timer called: timeout=", self.timeout)
                time.sleep(self.timeout)
                console.diag("timer triggered!")

                plt.close("all")
                print("closed all plots and the fig")
Exemple #3
0
def sync_run_ssh(caller,
                 box_addr,
                 box_cmd,
                 report_error=True,
                 capture_output=True,
                 capture_as_bytes=False):
    '''
    This can be used to execute a cmd on the remote box, provided that an XT key
    has previously been sent to the box with the 'xt keysend' command.

    Note:
        - we use the "-i <file>" option to send public half of keypair (avoid entering password)
        - we use the "-v" (verbose) option to avoid a "quick edit" mode non-responsive issue (avoid ENTER key pressing)
    '''

    ssh_parts = make_ssh_cmd_parts(box_addr, box_cmd, capture_output,
                                   capture_as_bytes)
    console.diag("  running SSH: " + " ".join(ssh_parts))

    exit_code, output = sync_run(ssh_parts,
                                 report_error=report_error,
                                 capture_output=capture_output,
                                 capture_as_bytes=capture_as_bytes)

    console.diag("  <script completed OK>")
    return exit_code, output
Exemple #4
0
def get_secret(name):
    name = correct_name(name)
    secrets = {}

    if os.path.exists(FN_SECRETS):
        text = file_utils.read_text_file(FN_SECRETS)
        secrets = json.loads(text)

    value = secrets[name] if name in secrets else None
    console.diag("get_secret: name={}, value={}".format(name, value))
    return value
Exemple #5
0
def sync_run(cmd_parts,
             capture_output=True,
             shell=False,
             report_error=False,
             env_vars=None,
             capture_as_bytes=False):
    ''' this does a synchronous run of the specified cmd/app and returns the app's exitcode. It runs
    in the current working directory, but target app MUST be a fully qualified path. '''
    universal_newlines = False

    #cmd = " ".join(cmd_parts) if isinstance(cmd_parts, list) else cmd_parts
    console.diag("sync_run: {}".format(cmd_parts))

    # linux won't accept a command, only cmd parts
    #assert isinstance(cmd_parts, (list, tuple))
    if isinstance(cmd_parts, str):
        cmd_parts = cmd_parts.split(" ")

    if capture_output:
        process = subprocess.run(cmd_parts,
                                 cwd=".",
                                 env=env_vars,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT,
                                 universal_newlines=universal_newlines,
                                 shell=shell)

        output = process.stdout

        if not capture_as_bytes:
            if not universal_newlines:
                # since universal_newlines=False, we need to map bytes to str
                output = output.decode("utf-8",
                                       errors='backslashreplace').replace(
                                           '\r', '')

            output = filter_out_verbose_lines(output)
    else:
        process = subprocess.run(cmd_parts, cwd=".", env=env_vars, shell=shell)
        output = None

    exit_code = process.returncode

    if report_error and exit_code:
        console.print(output)
        raise Exception("sync run failed, exit code={}, error={}".format(
            exit_code, output))

    return exit_code, output
Exemple #6
0
def set_secret(name, value):
    name = correct_name(name)
    console.diag("set_secret: name={}, value={}".format(name, value))

    file_utils.ensure_dir_exists(file=FN_SECRETS)

    secrets = {}

    # read existing secrets, if any
    if os.path.exists(FN_SECRETS):
        text = file_utils.read_text_file(FN_SECRETS)
        secrets = json.loads(text)

    secrets[name] = value

    # write updates secrets
    text = json.dumps(secrets)
    file_utils.write_text_file(FN_SECRETS, text)
Exemple #7
0
def scp_copy_file_to_box(caller,
                         box_addr,
                         fn_local,
                         box_fn,
                         report_error=True):
    #cmd = 'scp -i {} "{}" {}:{}'.format(constants.LOCAL_KEYPAIR_PRIVATE, fn_local, box_addr, box_fn)
    cmd_parts = [
        "scp", "-i",
        os.path.expanduser(constants.LOCAL_KEYPAIR_PRIVATE), fn_local,
        "{}:{}".format(box_addr, box_fn)
    ]
    console.diag("  copying script to box; cmd={}".format(cmd_parts))

    exit_code, output = sync_run(cmd_parts)
    if report_error and exit_code:
        console.print(output)
        raise Exception("scp copy command failed: {}".format(output))

    return exit_code, output
Exemple #8
0
    def _load_grok_creds(self):
        fn_keys = "keys.bin"
        loaded = False

        if not os.path.exists(fn_keys):
            fn_keys = os.path.expanduser("~/.xt/teams/{}/keys.bin".format(
                self.team_name))

        if os.path.exists(fn_keys):
            # GROK server creds
            creds = file_utils.read_text_file(fn_keys)
            self.apply_creds(creds)

            fn_cert = os.path.join(os.path.dirname(fn_keys), "xt_cert.pem")
            if os.path.exists(fn_cert):
                cert = file_utils.read_text_file(fn_keys)
                self.keys["xt_server_cert"] = cert

            console.diag("init_creds: using grok server 'keys.bin' file")
            loaded = True

        return loaded
    def read_file(self, fn, start_offset, end_offset):

        fn = file_utils.fix_slashes(fn, is_linux=True)

        # # leverage the read_file() function in psm.py
        # ssh_cmd = "cd ~/.xt/cwd; python -c 'import psm; psm.read_file(\"{}\", {}, {})'" \
        #     .format(fn, start_offset, end_offset)

        # error_code, read_bytes = process_utils.sync_run_ssh(None, self.box_addr, ssh_cmd, capture_as_bytes=True, report_error=False)
        new_bytes = b""

        try:
            with self.ftp_client.file(fn) as infile:
                infile.seek(start_offset)

                if end_offset:
                    new_bytes = infile.read(end_offset - start_offset) 
                else:
                    new_bytes = infile.read() 
        except BaseException as ex:
            console.diag("exception: ex={}".format(ex))

        #new_bytes = read_bytes if not error_code else b""
        return new_bytes
    def plot_data(self, data_frames_by_cols):
        console.diag("starting to plot data")

        # on-demand import for faster XT loading
        import seaborn as sns
        import matplotlib.pyplot as plt
        import matplotlib as mpl
        import pylab

        if not self.show_toolbar:
            # hide the ugly toolbar at bottom left of plot window
            mpl.rcParams['toolbar'] = 'None'

        # apply seaborn styling
        if self.style:
            sns.set_style(self.style)

        # decide how layout, titles, etc. will be set
        group_names = set()

        # gather group names (usually all are in the first dataset, but not always)
        for dfx in data_frames_by_cols.values():
            name_list = dfx[self.group_by].unique()
            group_names.update(set(name_list))

        group_names = list(group_names)

        # this will sort the group names in a number-smart way
        group_names.sort(key=utils.natural_keys)

        group_count = len(group_names)
        col_count = len(self.col_names)

        break_on_groups = self.break_on and ("run" in self.break_on
                                             or "group" in self.break_on)
        break_on_cols = self.break_on and "col" in self.break_on

        if break_on_groups and break_on_cols:
            plot_count = group_count * col_count
        elif break_on_groups:
            plot_count = group_count
        elif break_on_cols:
            plot_count = col_count
        else:
            plot_count = 1

        # calc true layout
        if self.layout:
            plot_rows, plot_cols = self.calc_actual_layout(
                plot_count, self.layout)
        else:
            plot_cols = plot_count
            plot_rows = 1

        runs_per_plot = 1 if break_on_groups else group_count
        cols_per_plot = 1 if break_on_cols else col_count

        if runs_per_plot == 1:
            plot_title = "$run"
            legend_text = "$col"
        elif cols_per_plot == 1:
            plot_title = "$col"
            legend_text = "$run"
        else:
            plot_title = None
            legend_text = "$col ($run)"

        if not self.plot_titles and plot_title:
            self.plot_titles = [plot_title]

        if not self.legend_titles:
            self.legend_titles = [legend_text]

        # configure matplotlib for our subplots
        sharex = True
        sharey = True

        #plt.close()
        window_size = (14, 6)

        fig, plots = plt.subplots(plot_rows,
                                  plot_cols,
                                  figsize=window_size,
                                  sharex=sharex,
                                  sharey=sharey,
                                  constrained_layout=True)
        if not isinstance(plots, np.ndarray):
            # make it consistent with plot_count > 1 plots
            plots = [plots]
        elif plot_rows > 1:
            plots = plots.flatten()

        fig.suptitle(self.title, fontsize=16)

        if self.timeout:
            # build a thread to close our plot window after specified time
            from threading import Thread

            def set_timer(timeout):
                console.print("set_timer called: timeout=", self.timeout)
                time.sleep(self.timeout)
                console.diag("timer triggered!")

                plt.close("all")
                print("closed all plots and the fig")

            thread = Thread(target=set_timer, args=[self.timeout])
            thread.daemon = True  # mark as background thread
            thread.start()

        line_index = 0
        plot_index = 0
        trace_count = 0
        x_label = self.x_label if self.x_label else self.x_col

        if self.aggregate == "none":
            self.aggregate = None

        if (self.aggregate and (break_on_cols and not break_on_groups)) \
            or ((not self.aggregate) and break_on_cols):
            # columns needs to be the outer loop
            for c, col in enumerate(self.col_names):

                if trace_count >= self.max_traces:
                    break

                if c and break_on_cols:
                    plot_index += 1
                    line_index = 0

                for r, group_name in enumerate(group_names):

                    if trace_count >= self.max_traces:
                        break

                    if r and break_on_groups:
                        plot_index += 1
                        line_index = 0

                    # PLOT MIDDLE
                    ax = plots[plot_index]  # .gca()
                    self.plot_middle(data_frames_by_cols, ax, group_name, col,
                                     self.x_col, x_label, line_index)
                    line_index += 1
                    trace_count += 1
        else:
            # run will work as the outer loop
            for r, group_name in enumerate(group_names):

                if trace_count >= self.max_traces:
                    break

                if r and break_on_groups:
                    plot_index += 1
                    line_index = 0

                for c, col in enumerate(self.col_names):

                    if trace_count >= self.max_traces:
                        break

                    if c and break_on_cols:
                        plot_index += 1
                        line_index = 0

                    # PLOT MIDDLE
                    ax = plots[plot_index]  #.gca()
                    self.plot_middle(data_frames_by_cols, ax, group_name, col,
                                     self.x_col, x_label, line_index)
                    line_index += 1
                    trace_count += 1

        if self.save_to:
            plt.savefig(self.save_to)

        if self.show_plot:
            pylab.show()