1#!/usr/bin/env python3
2
3r"""
4This file contains functions which are useful for processing BMC dumps.
5"""
6
7import gen_print as gp
8import gen_misc as gm
9import gen_robot_keyword as grk
10import bmc_ssh_utils as bsu
11import var_funcs as vf
12import os
13from robot.libraries.BuiltIn import BuiltIn
14import sys
15import os
16import imp
17base_path = os.path.dirname(os.path.dirname(
18                            imp.find_module("gen_robot_print")[1])) + os.sep
19sys.path.append(base_path + "data/")
20import variables as var
21
22
23def get_dump_dict(quiet=None):
24    r"""
25    Get dump information and return as an ordered dictionary where the keys
26    are the dump IDs and the values are the full path names of the dumps.
27
28    Example robot program call:
29
30    ${dump_dict}=  Get Dump Dict
31    Rprint Vars  dump_dict
32
33    Example output:
34
35    dump_dict:
36      [1]:
37      /var/lib/phosphor-debug-collector/dumps/1/obmcdump_1_1508255216.tar.xz
38      [2]:
39      /var/lib/phosphor-debug-collector/dumps/2/obmcdump_2_1508255245.tar.xz
40      [3]:
41      /var/lib/phosphor-debug-collector/dumps/3/obmcdump_3_1508255267.tar.xz
42      [4]:
43      /var/lib/phosphor-debug-collector/dumps/4/obmcdump_4_1508255283.tar.xz
44
45    Description of argument(s):
46    quiet                           If quiet is set to 1, this function will
47                                    NOT write status messages to stdout.
48    """
49
50    quiet = int(gp.get_var_value(quiet, 1))
51    cmd_buf = "dump_dir_path=" + var.DUMP_DIR_PATH + " ; " \
52              + "for dump_id in $(ls ${dump_dir_path} | sort -n) ; do " \
53              + "file_path=$(ls ${dump_dir_path}${dump_id}/* 2>/dev/null)" \
54              + " || continue ; echo ${dump_id}:${file_path} ; done"
55    output, stderr, rc = bsu.bmc_execute_command(cmd_buf, quiet=quiet)
56
57    return vf.key_value_outbuf_to_dict(output)
58
59
60def valid_dump(dump_id,
61               dump_dict=None,
62               quiet=None):
63    r"""
64    Verify that dump_id is a valid.  If it is not valid, issue robot failure
65    message.
66
67    A dump is valid if the indicated dump_id refers to an existing dump with a
68    valid associated dump file.
69
70    Description of argument(s):
71    dump_id                         A dump ID (e.g. "1", "2", etc.)
72    dump_dict                       A dump dictionary such as the one returned
73                                    by get_dump_dict.  If this value is None,
74                                    this function will call get_dump_dict on
75                                    the caller's behalf.
76    quiet                           If quiet is set to 1, this function will
77                                    NOT write status messages to stdout.
78    """
79
80    if dump_dict is None:
81        dump_dict = get_dump_dict(quiet=quiet)
82
83    if dump_id not in dump_dict:
84        message = "The specified dump ID was not found among the existing" \
85            + " dumps:\n"
86        message += gp.sprint_var(dump_id)
87        message += gp.sprint_var(dump_dict)
88        BuiltIn().fail(gp.sprint_error(message))
89
90    if not dump_dict[dump_id].endswith("tar.xz"):
91        message = "There is no \"tar.xz\" file associated with the given" \
92            + " dump_id:\n"
93        message += gp.sprint_var(dump_id)
94        dump_file_path = dump_dict[dump_id]
95        message += gp.sprint_var(dump_file_path)
96        BuiltIn().fail(gp.sprint_error(message))
97
98
99def scp_dumps(targ_dir_path,
100              targ_file_prefix="",
101              dump_dict=None,
102              quiet=None):
103    r"""
104    SCP all dumps from the BMC to the indicated directory on the local system
105    and return a list of the new files.
106
107    Description of argument(s):
108    targ_dir_path                   The path of the directory to receive the
109                                    dump files.
110    targ_file_prefix                Prefix which will be pre-pended to each
111                                    target file's name.
112    dump_dict                       A dump dictionary such as the one returned
113                                    by get_dump_dict.  If this value is None,
114                                    this function will call get_dump_dict on
115                                    the caller's behalf.
116    quiet                           If quiet is set to 1, this function will
117                                    NOT write status messages to stdout.
118    """
119
120    targ_dir_path = gm.add_trailing_slash(targ_dir_path)
121
122    if dump_dict is None:
123        dump_dict = get_dump_dict(quiet=quiet)
124
125    status, ret_values = grk.run_key("Open Connection for SCP", quiet=quiet)
126
127    dump_file_list = []
128    for dump_id, source_file_path in dump_dict.items():
129        targ_file_path = targ_dir_path + targ_file_prefix \
130            + os.path.basename(source_file_path)
131        status, ret_values = grk.run_key("scp.Get File  " + source_file_path
132                                         + "  " + targ_file_path, quiet=quiet)
133        dump_file_list.append(targ_file_path)
134
135    return dump_file_list
136
137
138def get_dump_hb_dict(quiet=None):
139    r"""
140    Get dump information and return as an ordered dictionary where the keys
141    are the dump IDs and the values are the full path names of the dumps.
142
143    Example robot program call:
144
145    ${dump_dict}=  Get Dump HB Dict
146    Rprint Vars  dump_hb_dict
147
148    Example output:
149
150    dump__hb_dict:
151      [1]:
152      /var/lib/phosphor-debug-collector/hostbootdump/1/hbdump_1_1621421112.tar.gz
153
154    Description of argument(s):
155    quiet                           If quiet is set to 1, this function will
156                                    NOT write status messages to stdout.
157    """
158
159    quiet = int(gp.get_var_value(quiet, 1))
160    cmd_buf = "dump_hb_dir_path=" + var.DUMP_HB_DIR_PATH + " ; " \
161              + "for dump_id in $(ls ${dump_hb_dir_path} | sort -n) ; do " \
162              + "file_path=$(ls ${dump_hb_dir_path}${dump_id}/* 2>/dev/null)" \
163              + " || continue ; echo ${dump_id}:${file_path} ; done"
164    output, stderr, rc = bsu.bmc_execute_command(cmd_buf, quiet=quiet)
165
166    return vf.key_value_outbuf_to_dict(output)
167
168
169def valid_dump_hb(dump_id,
170                  dump_dict=None,
171                  quiet=None):
172    r"""
173    Verify that dump_id is a valid.  If it is not valid, issue robot failure
174    message.
175
176    A dump is valid if the indicated dump_id refers to an existing dump with a
177    valid associated dump file.
178
179    Description of argument(s):
180    dump_id                         A dump ID (e.g. "1", "2", etc.)
181    dump_dict                       A dump dictionary such as the one returned
182                                    by get_dump_hb_dict.  If this value is None,
183                                    this function will call get_dump_hb_dict on
184                                    the caller's behalf.
185    quiet                           If quiet is set to 1, this function will
186                                    NOT write status messages to stdout.
187    """
188
189    if dump_dict is None:
190        dump_dict = get_dump_hb_dict(quiet=quiet)
191
192    if dump_id not in dump_dict:
193        message = "The specified dump ID was not found among the existing" \
194            + " dumps:\n"
195        message += gp.sprint_var(dump_id)
196        message += gp.sprint_var(dump_dict)
197        BuiltIn().fail(gp.sprint_error(message))
198
199    if not dump_dict[dump_id].endswith("tar.gz"):
200        message = "There is no \"tar.gz\" file associated with the given" \
201            + " dump_id:\n"
202        message += gp.sprint_var(dump_id)
203        dump_file_path = dump_dict[dump_id]
204        message += gp.sprint_var(dump_file_path)
205        BuiltIn().fail(gp.sprint_error(message))
206
207
208def scp_dumps_hb(targ_dir_path,
209                 targ_file_prefix="",
210                 dump_dict=None,
211                 quiet=None):
212    r"""
213    SCP all dumps from the BMC to the indicated directory on the local system
214    and return a list of the new files.
215
216    Description of argument(s):
217    targ_dir_path                   The path of the directory to receive the
218                                    dump files.
219    targ_file_prefix                Prefix which will be pre-pended to each
220                                    target file's name.
221    dump_dict                       A dump dictionary such as the one returned
222                                    by get_dump_dict.  If this value is None,
223                                    this function will call get_dump_dict on
224                                    the caller's behalf.
225    quiet                           If quiet is set to 1, this function will
226                                    NOT write status messages to stdout.
227    """
228
229    targ_dir_path = gm.add_trailing_slash(targ_dir_path)
230
231    if dump_dict is None:
232        dump_dict = get_dump_hb_dict(quiet=quiet)
233
234    status, ret_values = grk.run_key("Open Connection for SCP", quiet=quiet)
235
236    dump_file_list = []
237    for dump_id, source_file_path in dump_dict.items():
238        targ_file_path = targ_dir_path + targ_file_prefix \
239            + os.path.basename(source_file_path)
240        status, ret_values = grk.run_key("scp.Get File  " + source_file_path
241                                         + "  " + targ_file_path, quiet=quiet)
242        dump_file_list.append(targ_file_path)
243
244    return dump_file_list
245