diff --git a/Handlers/argParseHandler.py b/Handlers/argParseHandler.py index 142e14a..aa8be04 100644 --- a/Handlers/argParseHandler.py +++ b/Handlers/argParseHandler.py @@ -20,6 +20,7 @@ def __init__(self, test_data): parser.add_argument('--buildurl', type=str, help='custom build json url') parser.add_argument('--localjson', type=str, help='local json parsing') parser.add_argument('--template', type=str, help='For parsing local path or web url for template') + parser.add_argument('--meta-qcom', action='store_true', help='Enable meta-qcom specific auto-login for flasher boot method') logging.debug('Added optional arguments') if self.test_data is not None: @@ -63,3 +64,8 @@ def get_template_path(self): template_path = self.argument.template logging.debug(f'Template path: {template_path}') return template_path + + def is_meta_qcom_enabled(self): + meta_qcom_enabled = self.argument.meta_qcom + logging.debug(f'Meta-qcom enabled: {meta_qcom_enabled}') + return meta_qcom_enabled diff --git a/README.md b/README.md index 0402e6a..01b7c79 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ cd job_render # Usage - Set environment variables (BOOT_METHOD, TARGET, TARGET_DTB) in your shell before running the script using the export command. +Supported `BOOT_METHOD` values: `fastboot`, `u-boot`, `efi`, `flasher`. +When using `BOOT_METHOD=efi` or `BOOT_METHOD=flasher`, set `FLASH_IMAGE` (required) and optionally `FLASH_PORT`. +For `BOOT_METHOD=flasher`, pass `--meta-qcom` to enable the `auto_login` block (login prompt `login:`, user `root`). Example: ``` export BOOT_METHOD="fastboot" @@ -33,4 +36,3 @@ export TARGET_DTB="qcs6490-rb3gen2" # License job_render is licensed under the [*BSD-3-clause-clear License*](https://spdx.org/licenses/BSD-3-Clause-Clear.html). See [*LICENSE*](https://github.com/qualcomm-linux/job_render/blob/main/LICENSE) for the full license text. - diff --git a/data/cloudData.json b/data/cloudData.json index 3be6016..4144b13 100644 --- a/data/cloudData.json +++ b/data/cloudData.json @@ -17,7 +17,8 @@ "modules": "", "kselftest_tar_gz": "https://files.kernelci.org/kbuild-gcc-12-arm64-681a3b1cea9ae9de13450f99/kselftest.tar.gz", "ramdisk": "", - "firmware": "" + "firmware": "", + "flash_image": "" }, "data": { "kernel_revision": { diff --git a/data_validation/validate_data.py b/data_validation/validate_data.py index 1c183b1..16ecacb 100644 --- a/data_validation/validate_data.py +++ b/data_validation/validate_data.py @@ -4,7 +4,7 @@ import sys # Allowed boot methods -allowed_boot_methods = ['fastboot', 'u-boot'] +allowed_boot_methods = ['fastboot', 'u-boot', 'efi', 'flasher'] class Validator: @@ -23,7 +23,10 @@ def validate_platform_config(self): # Check if boot_method is valid if self.platform_config['boot_method'] not in allowed_boot_methods: return False, f"Invalid boot_method: {self.platform_config['boot_method']}. Allowed values are {allowed_boot_methods},use export command to set environment variables" - + + if self.platform_config['boot_method'] == 'efi' and not self.platform_config.get('flash_image'): + return False, "BOOT_METHOD 'efi' requires FLASH_IMAGE to be set" + return True, "Valid platform_config" @@ -57,4 +60,4 @@ def perform_validations_and_proceed(self): sys.exit(1) except Exception as e: print(f"An unexpected error occurred: {e}") - sys.exit(1) \ No newline at end of file + sys.exit(1) diff --git a/lava_Job_definition_generator.py b/lava_Job_definition_generator.py index fe514a8..dbcb434 100644 --- a/lava_Job_definition_generator.py +++ b/lava_Job_definition_generator.py @@ -17,6 +17,8 @@ boot_method = os.environ.get("BOOT_METHOD") name = os.environ.get("TARGET") target_dtb = os.environ.get("TARGET_DTB") +flash_image = os.environ.get("FLASH_IMAGE") +flash_port = os.environ.get("FLASH_PORT", "0") brarch = 'arm64' @@ -24,6 +26,10 @@ if not os.path.exists('logs'): os.makedirs('logs') +# Create renders directory if it doesn't exist +if not os.path.exists('renders'): + os.makedirs('renders') + # Generate a unique log file name based on the current timestamp log_filename = datetime.now().strftime('logs/log_%Y%m%d_%H%M%S.log') @@ -35,7 +41,8 @@ platform_config = { 'boot_method': boot_method, - 'name': name + 'name': name, + 'flash_image': flash_image } # Example test method, # → picks the value from the environment if it exists @@ -67,6 +74,7 @@ is_buildurl_provided = arg_parse_handler.get_buildurl() local_json_path = arg_parse_handler.get_local_json_path() template_path = arg_parse_handler.get_template_path() +meta_qcom_enabled = arg_parse_handler.is_meta_qcom_enabled() ### Error Handling for more than one arguments for json passing (options: build_url, node_id, localjson) class ConflictError(Exception): @@ -129,7 +137,7 @@ class ConflictError(Exception): ### Render the template with dynamic data node_data = data_handler.get_fetched_data() -job_definition = template_handler.render_template(template, node=data_handler.get_fetched_data(), platform_config=platform_config, test_method=test_method, tests_count=data_handler.get_count_of_tests(),device_dtb = node_data['artifacts']['dtb'],brarch=brarch) +job_definition = template_handler.render_template(template, node=data_handler.get_fetched_data(), platform_config=platform_config, test_method=test_method, tests_count=data_handler.get_count_of_tests(), device_dtb=node_data['artifacts']['dtb'], brarch=brarch, flash_port=flash_port, meta_qcom=meta_qcom_enabled) # Parse the rendered YAML and Save the rendered job definition -template_handler.save_rendered_template(job_definition, os.path.join('renders','lava_job_definition.yaml')) \ No newline at end of file +template_handler.save_rendered_template(job_definition, os.path.join('renders','lava_job_definition.yaml')) diff --git a/templates/boot/efi.jinja2 b/templates/boot/efi.jinja2 new file mode 100644 index 0000000..c516071 --- /dev/null +++ b/templates/boot/efi.jinja2 @@ -0,0 +1,84 @@ +{%- set flash_image_url = flash_image_url | default(platform_config.flash_image, true) -%} +{%- if flash_image_name is not defined and flash_image_url -%} +{%- set flash_image_name = flash_image_url.split('/')[-1] -%} +{%- endif -%} + +- deploy: + images: + image: +{% if flash_image_headers %} + headers: +{% for key, value in flash_image_headers.items() %} + {{ key }}: '{{ value }}' +{% endfor %} +{% endif %} + url: '{{ flash_image_url }}' + dtb: + url: '{{ node.artifacts.dtb }}' + kernel: + url: '{{ node.artifacts.kernel }}' + ramdisk: + {% if boot_commands == "ramdisk" %} + url: '{{ ramdiskroot }}/rootfs.cpio.gz' + {% else %} + url: 'https://storage.kernelci.org/images/rootfs/debian/bookworm-kselftest/20250724.0/{{ brarch }}/initrd.cpio.gz' + {% endif %} + compression: gz + format: cpio.newc + overlays: + lava: true +{% filter indent(width=10) %} +{% block testoverlays %}{% endblock %} +{% endfilter %} +{% set dtb = device_dtb.split('/')[-1] %} +{% if boot_commands == "ramdisk" %} +{% set ramdisk_name = "rootfs.cpio.gz" %} +{% else %} +{% set ramdisk_name = "initrd.cpio.gz" %} +{% endif %} + postprocess: + docker: + image: + steps: +{%- if node.data.kernel_type.endswith('.gz') %} + - gunzip Image.gz +{%- endif %} + - generate_boot_bins.sh efi --ramdisk {{ ramdisk_name }} --systemd-boot /artifacts/systemd/usr/lib/systemd/boot/efi/systemd-bootaa64.efi --stub /artifacts/systemd/usr/lib/systemd/boot/efi/linuxaa64.efi.stub --linux Image --cmdline "console=ttyMSM0,115200n8 copy-modules rootdelay=10 root=PARTLABEL=rootfs rw rootwait qcom_geni_serial.con_enabled=1" --output images + - generate_boot_bins.sh dtb --input {{ dtb }} --output images + - export IMAGE_PATH=$PWD + - cp overlay*.tar.gz overlay.tar.gz + - echo "OVERLAY=overlay.tar.gz" >> $IMAGE_PATH/flash.settings + - echo "OVERLAY_PATH=/" >> $IMAGE_PATH/flash.settings + - echo "ROOTFS_IMAGE=rootfs.img" >> $IMAGE_PATH/flash.settings + - echo "EFI=images/efi.bin" >> $IMAGE_PATH/flash.settings + - echo "DTB=images/dtb.bin" >> $IMAGE_PATH/flash.settings + - echo "DEVICE_TYPE={{ platform_config.name }}" >> $IMAGE_PATH/flash.settings + - echo "PORT={{ flash_port | default('0', true) }}" >> $IMAGE_PATH/flash.settings + - cat $IMAGE_PATH/flash.settings + timeout: + minutes: 60 + to: downloads + +- deploy: + to: flasher + images: + image: + url: 'downloads://{{ flash_image_name }}' + settings: + url: 'downloads://flash.settings' + overlay: + url: 'downloads://overlay.tar.gz' + timeout: + minutes: 15 +- boot: + prompts: + - '/ #' + failure_retry: 3 + timeout: + minutes: 10 + timeouts: + bootloader-commands: + minutes: 5 + auto-login-action: + minutes: 5 + method: minimal diff --git a/templates/boot/flasher.jinja2 b/templates/boot/flasher.jinja2 new file mode 100644 index 0000000..c347026 --- /dev/null +++ b/templates/boot/flasher.jinja2 @@ -0,0 +1,53 @@ +- deploy: + images: + image: + url: '{{ node.artifacts.flash_image }}' + postprocess: + docker: + image: ghcr.io/mwasilew/docker-mkbootimage:master + steps: + - export IMAGE_PATH=$PWD + - cp overlay*.tar.gz overlay.tar.gz + - echo "OVERLAY=overlay.tar.gz" >> $IMAGE_PATH/flash.settings + - echo "OVERLAY_PATH=/" >> $IMAGE_PATH/flash.settings + - echo "ROOTFS_IMAGE=rootfs.img" >> $IMAGE_PATH/flash.settings + - echo "DEVICE_TYPE={{ platform_config.name }}" >> $IMAGE_PATH/flash.settings + - echo "PORT=0" >> $IMAGE_PATH/flash.settings + - cat $IMAGE_PATH/flash.settings + timeout: + minutes: 30 + to: downloads +{% set flash_image_url = node.artifacts.flash_image %} +{% set flash_image_path = flash_image_url.split('?')[0] %} +{% set flash_image_name = flash_image_path.split('/')[-1] %} +- deploy: + images: + image: + url: 'downloads://{{ flash_image_name }}' + settings: + url: downloads://flash.settings + overlay: + url: downloads://overlay.tar.gz + timeout: + minutes: 10 + to: flasher +- boot: +{% if meta_qcom | default(false, true) %} + auto_login: + login_prompt: 'login:' + username: root + password_prompt: Password + password: oelinux123 +{% endif %} + prompts: + - root@{{ platform_config.name }} + - root@(.*):[/~]# + failure_retry: 3 + timeout: + minutes: 10 + timeouts: + bootloader-commands: + minutes: 3 + auto-login-action: + minutes: 10 + method: minimal