1
|
|
|
#!/usr/bin/python3 |
2
|
|
|
|
3
|
|
|
from __future__ import print_function |
4
|
|
|
|
5
|
|
|
""" |
6
|
|
|
Takes given XCCDF or DataStream and for every profile in it it generates one |
7
|
|
|
OpenSCAP HTML guide. Also generates an index file that lists all the profiles |
8
|
|
|
and allows the user to navigate between them. |
9
|
|
|
|
10
|
|
|
Author: Martin Preisler <[email protected]> |
11
|
|
|
""" |
12
|
|
|
|
13
|
|
|
import os.path |
14
|
|
|
import argparse |
15
|
|
|
import threading |
16
|
|
|
import sys |
17
|
|
|
|
18
|
|
|
import ssg.build_guides |
19
|
|
|
import ssg.xccdf |
20
|
|
|
import ssg.utils |
21
|
|
|
import ssg.xml |
22
|
|
|
|
23
|
|
|
|
24
|
|
|
def parse_args(): |
25
|
|
|
p = argparse.ArgumentParser() |
26
|
|
|
|
27
|
|
|
sp = p.add_subparsers(help="actions") |
28
|
|
|
|
29
|
|
|
make_sp = sp.add_parser("build", help="Build all the HTML guides") |
30
|
|
|
make_sp.set_defaults(cmd="build") |
31
|
|
|
|
32
|
|
|
input_sp = sp.add_parser("list-inputs", help="Generate input list") |
33
|
|
|
input_sp.set_defaults(cmd="list_inputs") |
34
|
|
|
|
35
|
|
|
output_sp = sp.add_parser("list-outputs", help="Generate output list") |
36
|
|
|
output_sp.set_defaults(cmd="list_outputs") |
37
|
|
|
|
38
|
|
|
p.add_argument("-j", "--jobs", type=int, action="store", |
39
|
|
|
default=ssg.utils.get_cpu_count(), |
40
|
|
|
help="how many jobs should be processed in parallel") |
41
|
|
|
p.add_argument("-i", "--input", action="store", required=True, |
42
|
|
|
help="input file, can be XCCDF or Source DataStream") |
43
|
|
|
p.add_argument("-o", "--output", action="store", required=True, |
44
|
|
|
help="output directory") |
45
|
|
|
|
46
|
|
|
return p.parse_args() |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
def main(): |
50
|
|
|
args = parse_args() |
51
|
|
|
|
52
|
|
|
input_path, input_basename, path_base, output_dir = \ |
53
|
|
|
ssg.build_guides.get_path_args(args) |
54
|
|
|
index_path = os.path.join(output_dir, "%s-guide-index.html" % (path_base)) |
55
|
|
|
|
56
|
|
|
if args.cmd == "list_inputs": |
57
|
|
|
print(input_path) |
58
|
|
|
sys.exit(0) |
59
|
|
|
|
60
|
|
|
input_tree = ssg.xml.ElementTree.parse(input_path) |
61
|
|
|
benchmarks = ssg.xccdf.get_benchmark_id_title_map(input_tree) |
62
|
|
|
if len(benchmarks) == 0: |
63
|
|
|
raise RuntimeError( |
64
|
|
|
"Expected input file '%s' to contain at least 1 xccdf:Benchmark. " |
65
|
|
|
"No Benchmarks were found!" % |
66
|
|
|
(input_path) |
67
|
|
|
) |
68
|
|
|
|
69
|
|
|
benchmark_profile_pairs = ssg.build_guides.get_benchmark_profile_pairs( |
70
|
|
|
input_tree, benchmarks) |
71
|
|
|
|
72
|
|
|
if args.cmd == "list_outputs": |
73
|
|
|
guide_paths = ssg.build_guides.get_output_guide_paths(benchmarks, |
74
|
|
|
benchmark_profile_pairs, |
75
|
|
|
path_base, output_dir) |
76
|
|
|
|
77
|
|
|
for guide_path in guide_paths: |
78
|
|
|
print(guide_path) |
79
|
|
|
print(index_path) |
80
|
|
|
sys.exit(0) |
81
|
|
|
|
82
|
|
|
index_links, index_options, index_initial_src, queue = \ |
83
|
|
|
ssg.build_guides.fill_queue(benchmarks, benchmark_profile_pairs, |
84
|
|
|
input_path, path_base, output_dir) |
85
|
|
|
|
86
|
|
|
workers = [] |
87
|
|
|
for worker_id in range(args.jobs): |
88
|
|
|
worker = threading.Thread( |
89
|
|
|
name="Guide generate worker #%i" % (worker_id), |
90
|
|
|
target=lambda queue=queue: ssg.build_guides.builder(queue) |
91
|
|
|
) |
92
|
|
|
workers.append(worker) |
93
|
|
|
worker.daemon = True |
94
|
|
|
worker.start() |
95
|
|
|
|
96
|
|
|
for worker in workers: |
97
|
|
|
worker.join() |
98
|
|
|
|
99
|
|
|
if queue.unfinished_tasks > 0: |
100
|
|
|
raise RuntimeError("Some of the guides were not exported successfully") |
101
|
|
|
|
102
|
|
|
index_source = ssg.build_guides.build_index(benchmarks, input_basename, |
103
|
|
|
index_links, index_options, |
104
|
|
|
index_initial_src) |
105
|
|
|
|
106
|
|
|
with open(index_path, "wb") as f: |
107
|
|
|
f.write(index_source.encode("utf-8")) |
108
|
|
|
|
109
|
|
|
|
110
|
|
|
if __name__ == "__main__": |
111
|
|
|
main() |
112
|
|
|
|