• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tfcollins / telemetry / 9971013826

17 Jul 2024 08:41AM UTC coverage: 56.673% (-1.6%) from 58.234%
9971013826

push

github

kimpaller
gist: support variant boards

Signed-off-by: kimpaller <kimchesed.paller@analog.com>

4 of 41 new or added lines in 2 files covered. (9.76%)

1 existing line in 1 file now uncovered.

637 of 1124 relevant lines covered (56.67%)

0.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

30.89
/telemetry/cli.py
1
"""Console script for telemetry."""
2
import sys
1✔
3
import click
1✔
4
import datetime
1✔
5
import telemetry
1✔
6
import os
1✔
7

8
import telemetry.report
1✔
9
from telemetry.report.utility import map_th_to_bp, map_bp_to_th
1✔
10

11
def validate(field, value, schema):
1✔
12
    """Validate a field and value data type
13
    againts a given es schema
14
    """
15
    properties = schema["mappings"]["properties"]
×
16
    type_maps = {
×
17
        "keyword" : "str",
18
        "text" : "str",
19
        "boolean" : "bool",
20
        "integer" : "int",
21
        "date" : "datetime"
22
    }
23
    if not field in properties.keys():
×
24
        raise Exception(f"Schema validator: {field} not supported")
×
25

26
    # Validate data type
27
    expected_type = type_maps[properties[field]["type"]]
×
28
    actual_type = type(value).__name__
×
29

30
    try:
×
31
        if not actual_type == expected_type:
×
32
            raise Exception(f"Schema validator: {field} expects {expected_type} type, {actual_type} is given")
×
33
    except Exception:
×
34
        if expected_type == "bool":
×
35
            if value.lower() in ["false", "true"]:
×
36
                value = bool(value)
×
37
        if expected_type == "int":
×
38
            value = int(value)
×
39

40
@click.group()
1✔
41
def cli():
1✔
42
    pass
×
43

44

45
@click.command()
1✔
46
@click.option(
1✔
47
    "--tdir",
48
    default="/test/logs/unprocessed",
49
    help="Path to directory of unprocessed test logs",
50
)
51
@click.option("--server", default=None, help="Address of mongo server")
1✔
52
@click.option("--username", default=None, help="Username for mongo server")
1✔
53
@click.option("--password", default=None, help="Password for mongo server")
1✔
54
@click.option("--dbname", default=None, help="Target collection for mongo server")
1✔
55
@click.option("--board", default=None, help="Name of target board")
1✔
56
def prod_logs_upload(tdir, server, username, password, dbname, board):
1✔
57
    """Upload unprocessed test logs to mongo for synchrona."""
58
    sync = telemetry.prod.BoardLog(server, username, password, dbname, board)
×
59
    sync.default_unprocessed_log_dir = tdir
×
60
    sync.default_processed_log_dir = os.path.join(tdir, "processed")
×
61
    if not os.path.isdir(sync.default_processed_log_dir):
×
62
        os.mkdir(sync.default_processed_log_dir)
×
63
    sync() # go go
×
64

65

66
@click.command()
1✔
67
@click.option("--server", default="picard", help="Address of Elasticsearch server")
1✔
68
@click.option(
1✔
69
    "--filename",
70
    default="resource_utilization.csv",
71
    help="Full path to resource utilization csv file generated by HDL builds",
72
)
73
def log_hdl_resources_from_csv(server, filename):
1✔
74
    tel = telemetry.ingest(server=server)
×
75
    tel.log_hdl_resources_from_csv(filename)
×
76

77

78
@click.command()
1✔
79
@click.option("--server", default="picard", help="Address of Elasticsearch server")
1✔
80
@click.argument("in_args", nargs=-1)
1✔
81
def log_artifacts(server, in_args):
1✔
82
    entry = {
×
83
        "url": "NA",
84
        "server": "NA",
85
        "job": "NA",
86
        "job_no": 0,
87
        "job_date": None,
88
        "job_build_parameters": "NA",
89
        "file_name": "NA",
90
        "target_board": "NA",
91
        "artifact_info_type": "NA",
92
        "payload_raw": "NA",
93
        "payload_ts": "NA",
94
        "payload": "NA",
95
        "payload_param": "NA"
96
    }
97
    if len(in_args) == 0:
×
98
        click.echo("Must have non-zero arguments for database entry")
×
99
        sys.exit(1)
×
100
    if int(len(in_args) / 2) != len(in_args) / 2:
×
101
        click.echo(
×
102
            "ERROR: Number of inputs arguments must be even\n"
103
            + "       and in the form of: entry1<space>value1<space>entry2<space>value2"
104
        )
105
        sys.exit(1)
×
106
    for i in range(0, len(in_args), 2):
×
107
        if in_args[i] in entry:
×
108
            if in_args[i + 1].lower() == "true":
×
109
                entry[in_args[i]] = True
×
110
            elif in_args[i + 1].lower() == "false":
×
111
                entry[in_args[i]] = False
×
112
            else:
113
                entry[in_args[i]] = in_args[i + 1]
×
114
        else:
115
            click.echo("ERROR: " + in_args[i] + " not a valid entry")
×
116
            sys.exit(1)
×
117
    tel = telemetry.ingest(server=server)
×
118
    tel.log_artifacts(**entry)
×
119

120
@click.command()
1✔
121
@click.option("--jenkins-server", required=True, help="Address of Jenkins server")
1✔
122
@click.option("--jenkins-username", required=False, help="Username with access on the Jenkins server")
1✔
123
@click.option("--jenkins-password", required=False, help="Password for Jenkins username")
1✔
124
@click.option("--es-server", required=True, help="Address of Elasticsearch server")
1✔
125
@click.option("--job-name", default="HW_tests/HW_test_multiconfig", help="Name of Jenkins job")
1✔
126
@click.option("--job", multiple=True, help="Job(s)/build(s) to process")
1✔
127
def grab_and_log_artifacts(
1✔
128
        jenkins_server,
129
        jenkins_username,
130
        jenkins_password,
131
        es_server,
132
        job_name,
133
        job
134
    ):
135
    if not len(job) > 0:
×
136
        click.echo("Atleast 1 Job/Build (--job) is needed.")
×
137
        sys.exit(1)
×
138
    g = telemetry.gargantua(
×
139
        jenkins_server,
140
        jenkins_username,
141
        jenkins_password,
142
        es_server,
143
        job_name,
144
        job
145
    )
146
    g.log_artifacts()
×
147

148
@click.command()
1✔
149
@click.option("--server", default="picard", help="Address of Elasticsearch server")
1✔
150
@click.argument("in_args", nargs=-1)
1✔
151
def log_boot_logs(server, in_args):
1✔
152
    
153
    tel = telemetry.ingest(server=server)
×
154
    schema = tel.db.import_schema(tel._get_schema("boot_tests.json"))
×
155
    entry = dict()
×
156
    for k,v in schema["mappings"]["properties"].items():
×
157
        if k == "source_adjacency_matrix":
×
158
            continue
×
159
        if v["type"] in ["txt","keyword"]:
×
160
            entry.update({k:"NA"})
×
161
        elif v["type"] in ["integer"]:
×
162
            entry.update({k: 0})
×
163
        elif v["type"] in ["boolean"]:
×
164
            entry.update({k: False})
×
165
        elif k == "jenkins_job_date":
×
166
            entry.update({k:datetime.datetime.now()})
×
167
        else:
168
            entry.update({k: None})
×
169

170
    if len(in_args) == 0:
×
171
        click.echo("Must have non-zero arguments for database entry")
×
172
        sys.exit(1)
×
173
    if int(len(in_args) / 2) != len(in_args) / 2:
×
174
        click.echo(
×
175
            "ERROR: Number of inputs arguments must be even\n"
176
            + "       and in the form of: entry1<space>value1<space>entry2<space>value2"
177
        )
178
        sys.exit(1)
×
179

180
    for i in range(0, len(in_args), 2):
×
181
        if in_args[i] in entry:
×
182
            validate(in_args[i], in_args[i+1],schema)
×
183
            if in_args[i + 1].lower() == "true":
×
184
                entry[in_args[i]] = True
×
185
            elif in_args[i + 1].lower() == "false":
×
186
                entry[in_args[i]] = False
×
187
            else:
188
                entry[in_args[i]] = in_args[i + 1]
×
189
        else:
190
            click.echo("ERROR: " + in_args[i] + " not a valid entry")
×
191
            sys.exit(1)
×
192

193
    tel = telemetry.ingest(server=server)
×
194
    tel.log_boot_tests(**entry)
×
195

196
@click.command()
1✔
197
@click.option("--server", default="picard", help="Address of Elasticsearch server")
1✔
198
@click.option("--job_name", required=True, help="Jenkisn job name to fetch")
1✔
199
@click.option("--build_number", required=True, help="Build no to fetch")
1✔
200
@click.option("--board_name", default=None, help="Board to fetch, will select all if empty")
1✔
201
@click.option("--github_gist_url", default=None, help="Base URL to the gist repository")
1✔
202
@click.option("--github_gist_token", default=None, help="Token required for gist access")
1✔
203
def create_results_gist(server, job_name, build_number, board_name, github_gist_url, github_gist_token):
1✔
204
    tel = telemetry.searches(server=server)
×
205
    boot_test = tel.boot_tests(
×
206
        boot_folder_name=board_name,
207
        jenkins_project_name=job_name,
208
        jenkins_build_no=build_number
209
    )
210

211
    if len(boot_test.keys()) == 0:
×
212
        raise Exception(f"{job_name} - {build_number} not found")
×
213
    # get artifacts
UNCOV
214
    artifacts_info_txt=tel.artifacts(
×
215
        target_board=None,
216
        job=job_name,
217
        job_no = build_number,
218
        artifact_info_type = "info_txt",
219
    )
220
    built_projects = list()
×
NEW
221
    translated_built_projects = list()
×
NEW
222
    data = {}
×
NEW
223
    translated_data = {}
×
224
    for artifact in artifacts_info_txt:
×
225
        if artifact["payload"] == "Built projects":
×
226
            built_projects.append(artifact["payload_param"])
×
227

228
    # translate first to test harness board naming scheme
229
    for board in built_projects:
×
NEW
230
        translated = map_bp_to_th(board)
×
NEW
231
        if translated:
×
NEW
232
            if type(translated) == list:
×
NEW
233
                for variant in translated:
×
NEW
234
                    if variant not in translated_built_projects:
×
NEW
235
                        translated_built_projects.append(variant)
×
236
            else:
NEW
237
                translated_built_projects.append(translated)
×
238
        else:
NEW
239
            translated_built_projects.append(board)
×
240

NEW
241
    for board in translated_built_projects:
×
242
        if not board in boot_test.keys():
×
243
            data[board] = "NA"
×
244
        else:
245
            info = boot_test[board]
×
246
            artifacts = tel.artifacts(board, job_name, build_number)
×
247
            artifact_types = ["enumerated_devs", "missing_devs", "dmesg_err", "pytest_failure"]
×
248
            for artifactory_type in artifact_types:
×
249
                info[0].update({artifactory_type: []})
×
250
                for artifact in artifacts:
×
251
                    if artifact["artifact_info_type"] == artifactory_type:
×
252
                        info[0][artifactory_type].append(artifact["payload"])
×
253
            
254
            if artifacts_info_txt:
×
255
                info[0]["info_txt"] = dict()
×
256
                info[0]["info_txt"].update({"Built projects": list()})
×
257
                for artifact in artifacts_info_txt:
×
258
                    if artifact["payload"] == "Built projects":
×
259
                        info[0]["info_txt"]["Built projects"].append(artifact["payload_param"])
×
260
                        continue
×
261
                    info[0]["info_txt"].update({artifact["payload"]:artifact["payload_param"]})
×
262

263
            
NEW
264
            info[0]["variance_info"] = board.split("-v")[1] if len(board.split("-v")) == 2 else None
×
NEW
265
            data[board] = info[0]
×
266

267
    # translate back to boot partition naming scheme
NEW
268
    for bn, details in data.items():
×
NEW
269
        translated = map_th_to_bp(bn)
×
NEW
270
        if translated:
×
NEW
271
            board_name = translated
×
272
        else:
NEW
273
            board_name = bn
×
NEW
274
        if board_name in translated_data:
×
NEW
275
            board_name += f" ({details['variance_info']})"
×
NEW
276
        translated_data.update({board_name: details})
×
277

NEW
278
    m = telemetry.markdown.ResultsMarkdown(translated_data)
×
279
    m.generate_gist(github_gist_url, github_gist_token)
×
280
    
281
@click.command()
1✔
282
def main(args=None):
1✔
283
    """Console script for telemetry."""
284
    click.echo("Replace this message by putting your code into " "telemetry.cli.main")
1✔
285
    click.echo("See click documentation at https://click.palletsprojects.com/")
1✔
286
    return 0
1✔
287

288

289
cli.add_command(prod_logs_upload)
1✔
290
cli.add_command(log_boot_logs)
1✔
291
cli.add_command(log_hdl_resources_from_csv)
1✔
292
cli.add_command(log_artifacts)
1✔
293
cli.add_command(grab_and_log_artifacts)
1✔
294
cli.add_command(create_results_gist)
1✔
295
cli.add_command(main)
1✔
296

297
if __name__ == "__main__":
1✔
298
    sys.exit(cli())  # pragma: no cover
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc