Skip to content

Commit 8faac3b

Browse files
author
Robert Foley
committed
Added support for build_image.py in ssh mode to
automatically determine the .yml name in the case where the image was created as part of install_kernel.py. Also split out some common routines into a separate base command class.
1 parent 0d57ee5 commit 8faac3b

5 files changed

Lines changed: 131 additions & 107 deletions

File tree

external/qemu

scripts/base_cmd.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#
2+
# Copyright 2019 Linaro
3+
#
4+
# Base class for our command objects.
5+
#
6+
7+
import sys
8+
import os
9+
import stat
10+
import shutil
11+
import subprocess
12+
from subprocess import Popen,PIPE
13+
import argparse
14+
import yaml
15+
16+
class BaseCmd:
17+
18+
def __init__(self):
19+
self.kernel_ver = None
20+
self.kernel_ver_minor = None
21+
self._debug = False
22+
self._dry_run = False
23+
24+
def set_debug(self, debug):
25+
self._debug = debug
26+
27+
def set_dry_run(self, dry_run):
28+
self._dry_run = dry_run
29+
30+
def print(self, trace, debug=False):
31+
if not debug or self._debug:
32+
print("{}: {}".format(sys.argv[0], trace))
33+
34+
def terminate(self, err):
35+
if not self.continue_on_error:
36+
exit(err)
37+
38+
def issue_cmd(self, cmd, show_cmd=False, fail_on_err=True,
39+
err_msg=None, enable_stdout=True, no_capture=False):
40+
rc, output = self.run_command(cmd, show_cmd, enable_stdout=enable_stdout, no_capture=no_capture)
41+
if fail_on_err and rc != 0:
42+
self.print("cmd failed with status: {} cmd: {}".format(rc, cmd))
43+
if (err_msg):
44+
self.print(err_msg)
45+
self.terminate(1)
46+
return rc, output
47+
48+
def run_command(self, command, show_cmd=False, enable_stdout=True, no_capture=False):
49+
output_lines = []
50+
if show_cmd or self._debug:
51+
print("{}: {} ".format(sys.argv[0], command))
52+
if self._dry_run:
53+
print("")
54+
return 0, output_lines
55+
if no_capture:
56+
rc = subprocess.call(command, shell=True)
57+
return rc, output_lines
58+
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE) #shlex.split(command)
59+
while True:
60+
output = process.stdout.readline()
61+
if (not output or output == '') and process.poll() is not None:
62+
break
63+
if output and enable_stdout:
64+
self.print(str(output, 'utf-8').strip())
65+
output_lines.append(str(output, 'utf-8'))
66+
rc = process.poll()
67+
return rc, output_lines
68+
69+
def get_kernel_img_version(self, image):
70+
if self.kernel_ver:
71+
return
72+
entries = image.split("-")
73+
if len(entries) > 2:
74+
self.kernel_ver_minor = "{}-{}".format(entries[1], entries[2])
75+
self.kernel_ver = entries[1]
76+
if self.kernel_ver == None:
77+
raise Exception("Unable to determine kernel version, "\
78+
"please use --kernel_ver argument.")
79+
self.print("Kernel version is:"\
80+
" {} ({})".format(self.kernel_ver, self.kernel_ver_minor),
81+
debug=True)
82+
83+
def get_kernel_pkg_version(self, kernel_pkg_path):
84+
if self.kernel_ver:
85+
return
86+
cmd = "dpkg --info {}".format(kernel_pkg_path)
87+
rc, output = self.issue_cmd(cmd)
88+
for line in output:
89+
if "Version: " in line:
90+
entries = line.split(" ")
91+
if len(entries) > 2:
92+
self.kernel_ver_minor = entries[2].rstrip()
93+
self.kernel_ver = entries[2].split("-")[0].rstrip()
94+
if self.kernel_ver == None:
95+
raise Exception("Unable to determine kernel version, "\
96+
"please use --kernel_ver argument.")
97+
self.print("Kernel version is:"\
98+
" {} ({})".format(self.kernel_ver, self.kernel_ver_minor),debug=True)

scripts/build_image.py

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
import argparse
2222
from argparse import RawTextHelpFormatter
2323
import yaml
24+
import base_cmd
2425

25-
class build_image:
26+
class BuildImage(base_cmd.BaseCmd):
2627
qemu_path_rel = "external/qemu"
2728
qemu_build_path_rel = "external/qemu/build"
2829
build_path_rel = "build"
@@ -34,6 +35,7 @@ class build_image:
3435
key_files = ["id_rsa", "id_rsa.pub"]
3536

3637
def __init__(self, ssh=False):
38+
super(BuildImage, self).__init__()
3739
self.script_path = os.path.dirname(os.path.realpath(__file__))
3840
self.root_path = os.path.realpath(os.path.join(self.script_path, "../"))
3941
self.orig_default_config_path = os.path.realpath(os.path.join(self.root_path,
@@ -46,6 +48,8 @@ def __init__(self, ssh=False):
4648
else:
4749
self.default_config_path = self.orig_default_config_path
4850
self.parse_args()
51+
self.set_debug(self._args.debug)
52+
self.set_dry_run(self._args.dry_run)
4953
self.build_path = os.path.realpath(os.path.join(self.root_path, self.build_path_rel))
5054
self.qemu_build_path = os.path.realpath(os.path.join(self.root_path,
5155
self.qemu_build_path_rel))
@@ -64,6 +68,16 @@ def __init__(self, ssh=False):
6468
self.print("config file: {}".format(self.config_path), debug=True)
6569
self.continue_on_error = self._args.debug
6670
self.vm_config_path = os.path.join(self.image_dir_path, "conf.yml")
71+
image_name = os.path.basename(self.image_path)
72+
if ".kernel-" in image_name:
73+
self.get_kernel_img_version(image_name)
74+
kernel_config_file = os.path.join(self.image_dir_path,
75+
"conf-kernel-{}.yml".format(self.kernel_ver_minor))
76+
if os.path.exists(kernel_config_file):
77+
self.print("using kernel config: {}".format(kernel_config_file),
78+
debug=True)
79+
self.vm_config_path = kernel_config_file
80+
6781
self.src_ssh_key = os.path.join(self.def_key_path, "id_rsa")
6882
self.dest_ssh_key = os.path.join(self.image_dir_path, "id_rsa")
6983
self.src_ssh_pub_key = os.path.join(self.def_key_path, "id_rsa.pub")
@@ -81,45 +95,6 @@ def __init__(self, ssh=False):
8195
if self.start_ssh and not self.building_image and \
8296
self._args.config != self.orig_default_config_path:
8397
self.vm_config_path = self._args.config
84-
85-
86-
def print(self, trace, debug=False):
87-
if not debug or self._args.debug:
88-
print("{}: {}".format(sys.argv[0], trace))
89-
90-
def terminate(self, err):
91-
if not self.continue_on_error:
92-
exit(err)
93-
94-
def issue_cmd(self, cmd, show_cmd=False, fail_on_err=True, err_msg=None, enable_stdout=True, no_capture=False):
95-
rc, output = self.run_command(cmd, show_cmd, enable_stdout=enable_stdout, no_capture=no_capture)
96-
if fail_on_err and rc != 0:
97-
self.print("cmd failed with status: {} cmd: {}".format(rc, cmd))
98-
if (err_msg):
99-
self.print(err_msg)
100-
self.terminate(1)
101-
return rc, output
102-
103-
def run_command(self, command, show_cmd=False, enable_stdout=True, no_capture=False):
104-
output_lines = []
105-
if show_cmd or self._args.debug:
106-
print("{}: {} ".format(sys.argv[0], command))
107-
if self._args.dry_run:
108-
print("")
109-
return 0, output_lines
110-
if no_capture:
111-
rc = subprocess.call(command, shell=True)
112-
return rc, output_lines
113-
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE) #shlex.split(command)
114-
while True:
115-
output = process.stdout.readline()
116-
if (not output or output == '') and process.poll() is not None:
117-
break
118-
if output and enable_stdout:
119-
self.print(str(output, 'utf-8').strip())
120-
output_lines.append(str(output, 'utf-8'))
121-
rc = process.poll()
122-
return rc, output_lines
12398

12499
def parse_args(self):
125100
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter,
@@ -280,6 +255,8 @@ def ssh(self):
280255
debug = "--debug"
281256
else:
282257
debug = ""
258+
print("Launching Image. Please be patient, this may take several minutes...")
259+
print("To enable more verbose tracing of each step, please use the --debug option.\n")
283260
cmd = self.launch_cmd.format(env_vars, self._args.image_type, self.image_path, debug, "/bin/bash")
284261
self.issue_cmd(cmd, no_capture=True)
285262

@@ -308,5 +285,5 @@ def run(self):
308285
self.ssh()
309286

310287
if __name__ == "__main__":
311-
inst_obj = build_image()
288+
inst_obj = BuildImage()
312289
inst_obj.run()

scripts/install_kernel.py

Lines changed: 13 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@
2525
import traceback
2626
import re
2727
import yaml
28+
import base_cmd
2829

2930

30-
class install_kernel:
31+
class InstallKernel(base_cmd.BaseCmd):
3132
mount_path = "./mnt"
3233
host_tmp = "/tmp"
3334
mount_tmp = os.path.join(mount_path, "tmp")
@@ -49,6 +50,7 @@ class install_kernel:
4950
build_path_rel = "build"
5051

5152
def __init__(self):
53+
super(InstallKernel, self).__init__()
5254
self._image_mounted = False
5355

5456
self.device = None
@@ -67,6 +69,8 @@ def __init__(self):
6769
self._image_dir_path = os.path.join(self.build_path, "VM-" + "ubuntu.aarch64")
6870
self._default_image_path = os.path.join(self._image_dir_path, self.default_image_name)
6971
self.parse_args()
72+
self.set_debug(self._args.debug)
73+
self.set_dry_run(self._args.dry_run)
7074
self._image_path = os.path.abspath(getattr(self._args, 'image'))
7175
self._image_dir_path = os.path.dirname(self._image_path)
7276
self.vm_config_path = os.path.join(self._image_dir_path, "conf.yml")
@@ -75,54 +79,17 @@ def __init__(self):
7579
self.kernel_ver = self._args.kernel_ver
7680
self._kernel_pkg_name = os.path.basename(self._args.kernel_pkg)
7781
self._kernel_pkg_path = os.path.abspath(self._args.kernel_pkg)
78-
self.get_kernel_version()
82+
self.get_kernel_pkg_version(self._kernel_pkg_path)
7983
self.kernel_config_path = os.path.join(self._image_dir_path,
80-
"conf-{}.yml".format(self.kernel_ver_minor))
81-
self._output_image_path = self._image_path + '.kernel-' + self.kernel_ver
84+
"conf-kernel-{}.yml".format(self.kernel_ver_minor))
85+
self._output_image_path = self._image_path + '.kernel-' + self.kernel_ver_minor
8286
self._config_path = os.path.abspath(self._args.config)
8387
self._install_pkg_vm_path =os.path.join(self.install_pkg_vm_path, self._kernel_pkg_name)
8488
self.chroot_cmd = "chroot {} {}".format(self._mount_path,
8589
os.path.join(self.qemu_static_path,
8690
self.qemu_static_name))
8791
self.print("image_path: " + self._image_path)
8892
self.print("kernel_pkg_name: " + self._kernel_pkg_name)
89-
90-
def print(self, trace):
91-
print("{}: {}".format(sys.argv[0], trace))
92-
93-
def terminate(self, err):
94-
if not self.continue_on_error:
95-
exit(err)
96-
97-
def issue_cmd(self, cmd, fail_on_err=True, err_msg=None, enable_stdout=True, no_capture=False):
98-
rc, output = self.run_command(cmd, enable_stdout=enable_stdout, no_capture=no_capture)
99-
if fail_on_err and rc != 0:
100-
self.print("cmd failed with status: {} cmd: {}".format(rc, cmd))
101-
if (err_msg):
102-
self.print(err_msg)
103-
self.terminate(1)
104-
return rc, output
105-
106-
def run_command(self, command, enable_stdout=True, no_capture=False):
107-
output_lines = []
108-
if self._args.debug:
109-
print("{}: {}".format(sys.argv[0], command))
110-
if self._args.dry_run:
111-
print("")
112-
return 0, output_lines
113-
if no_capture:
114-
rc = subprocess.call(command, shell=True)
115-
return rc, output_lines
116-
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE) #shlex.split(command)
117-
while True:
118-
output = process.stdout.readline()
119-
if (not output or output == '') and process.poll() is not None:
120-
break
121-
if output and enable_stdout:
122-
self.print(str(output, 'utf-8').strip())
123-
output_lines.append(str(output, 'utf-8'))
124-
rc = process.poll()
125-
return rc, output_lines
12693

12794
def parse_args(self):
12895
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter,
@@ -234,28 +201,11 @@ def move_old_kernels(self, root_path="/"):
234201
for pattern in copy_patterns:
235202
for file in glob.glob(os.path.join(src_path, pattern)):
236203
if (self.kernel_ver not in file):
237-
self.print("move {} to {}".format(file, dest_path))
204+
self.print("move {} to {}".format(file, dest_path),
205+
debug=True)
238206
cmd = "mv {} {}".format(file, dest_path)
239207
self.issue_cmd(cmd)
240208

241-
def get_kernel_version(self):
242-
if self.kernel_ver:
243-
return
244-
#Description: Linux kernel, version 5.4.0+
245-
cmd = "dpkg --info {}".format(self._kernel_pkg_path)
246-
rc, output = self.issue_cmd(cmd)
247-
self.kernel_ver = None
248-
self.kernel_ver_minor = None
249-
for line in output:
250-
if "Version: " in line:
251-
entries = line.split(" ")
252-
if len(entries) > 2:
253-
self.kernel_ver_minor = entries[2].rstrip()
254-
self.kernel_ver = entries[2].split("-")[0].rstrip()
255-
if self.kernel_ver == None:
256-
raise Exception("Unable to determine kernel version, please use --kernel_ver argument.")
257-
self.print("Kernel version is: {} ({})".format(self.kernel_ver, self.kernel_ver_minor))
258-
259209
def install_pkg(self):
260210
cmd = self.kernel_pkg_cpy_cmd.format(self._kernel_pkg_path)
261211
self.issue_cmd(cmd)
@@ -296,7 +246,7 @@ def read_config(self):
296246
print("default config file {} does not exist. Continuing.")
297247
return None
298248
with open(self.vm_config_path) as f:
299-
print("parse {}".format(self.vm_config_path))
249+
self.print("parse {}".format(self.vm_config_path))
300250
yaml_dict = yaml.safe_load(f)
301251
if 'qemu-conf' in yaml_dict:
302252
return yaml_dict
@@ -310,7 +260,6 @@ def get_qemu_args_for_kernel(self, existing_args):
310260
"initrd.img-{}".format(self.kernel_ver_minor))
311261
args = "-kernel {} --initrd {}".format(vmlinuz_path, initrd_path)
312262
args += ' -append "root=/dev/vda1 nokaslr console=ttyAMA0"'
313-
print(args)
314263
return existing_args + " " + args
315264

316265
def create_config_file(self):
@@ -324,7 +273,7 @@ def create_config_file(self):
324273
yaml_dict['qemu-conf']['qemu_args'] = new_args
325274
with open(self.kernel_config_path, 'w') as f:
326275
yaml_dict = yaml.dump(yaml_dict, f)
327-
print("config file {} written".format(self.kernel_config_path))
276+
self.print("config file {} written".format(self.kernel_config_path))
328277

329278
def run_cmd_in_vm(self):
330279
env_vars = "QEMU=./aarch64-softmmu/qemu-system-aarch64 "
@@ -392,5 +341,5 @@ def run(self):
392341
self.cleanup()
393342

394343
if __name__ == "__main__":
395-
inst_obj = install_kernel()
344+
inst_obj = InstallKernel()
396345
inst_obj.run()

scripts/launch_image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
import build_image
77

88
if __name__ == "__main__":
9-
inst_obj = build_image.build_image(ssh=True)
9+
inst_obj = build_image.BuildImage(ssh=True)
1010
inst_obj.run()

0 commit comments

Comments
 (0)