def _mount_local(self, file_name_no_extension): """ Mount a image-file to a class-defined folder. Aborts if the mount command fails. Args: file_name_no_extension (str): The file name of the image that will be flashed on the device Returns: None """ logger.info( "Mounting the root partition for ssh-key and USB-networking " + "service injection.") try: common.make_directory(self._LOCAL_MOUNT_DIR) root_file_system_file = file_name_no_extension + "." + \ self._root_extension # guestmount allows us to mount the image without root privileges subprocess32.check_call( ["guestmount", "-a", root_file_system_file, "-m", "/dev/sda", self._LOCAL_MOUNT_DIR]) except subprocess32.CalledProcessError as err: logger.info("Failed to mount.") common.log_subprocess32_error_and_abort(err)
def _write_root_partition_files(self): """ Untar root fs into the root partition and copy device tree blob Returns: None """ try: # this can be slow, so give it plenty of time before timing out ssh.remote_execute( self.dev_ip, [ "tar", "--xattrs", "--xattrs-include=\"*\"", "-xvf", self.root_tarball, "-C", self.mount_dir], timeout=self._ROOTFS_WRITING_TIMEOUT) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err) dtb_target = os.path.join( self.mount_dir, "boot", "am335x-boneblack.dtb") self._copy_file_over_ssh(self.dtb_file, dtb_target)
def _mount_local(self, file_name_no_extension): """ Mount a image-file to a class-defined folder. Aborts if the mount command fails. Args: file_name_no_extension (str): The file name of the image that will be flashed on the device Returns: None """ logger.info( "Mounting the root partition for ssh-key and USB-networking " + "service injection.") try: common.make_directory(self._LOCAL_MOUNT_DIR) root_file_system_file = file_name_no_extension + "." + \ self._root_extension subprocess32.check_call( ["mount", root_file_system_file, self._LOCAL_MOUNT_DIR]) except subprocess32.CalledProcessError as err: logger.info("Failed to mount.") common.log_subprocess32_error_and_abort(err)
def _write_root_partition_files(self): """ Untar root fs into the root partition and copy device tree blob Returns: None """ try: # this can be slow, so give it plenty of time before timing out ssh.remote_execute(self.dev_ip, [ "tar", "--xattrs", "--xattrs-include=\"*\"", "-xvf", self.root_tarball, "-C", self.mount_dir ], timeout=self._ROOTFS_WRITING_TIMEOUT) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err) # Copy dtb file if there isn't one in the image boot_dir = os.path.join(self.mount_dir, "boot") boot_files = ssh.remote_execute(self.dev_ip, ["ls", boot_dir]) if "am335x-boneblack.dtb" not in boot_files: dtb_target = os.path.join(self.mount_dir, "boot", "am335x-boneblack.dtb") self._copy_file_over_ssh(self.dtb_file, dtb_target)
def _change_permissions_over_ssh(self, file_name, permission): """ Change file/directory permissions safely over ssh """ try: ssh.remote_execute(self.dev_ip, ["chmod", permission, file_name]) except subprocess32.CalledProcessError, err: common.log_subprocess32_error_and_abort(err)
def _unmount_over_ssh(self): """ Unmount the mounted directory at self.mount_dir Returns: None """ logger.info("Unmounting " + self.mount_dir) try: ssh.remote_execute(self.dev_ip, ["umount", self.mount_dir]) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err)
def _make_directory_over_ssh(self, directory): """ Make directory safely over ssh or abort on failure Args: directory (str): The directory that will be created Returns: None """ try: ssh.remote_execute(self.dev_ip, ["mkdir", "-p", directory]) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err)
def _copy_file_over_ssh(self, src, dst): """ Copy file safely over ssh or abort on failure Args: src (str): Source file dst (str): Destination file Returns: None """ try: ssh.remote_execute(self.dev_ip, ["cp", src, dst]) except subprocess32.CalledProcessError, err: common.log_subprocess32_error_and_abort(err)
def _make_directory_over_ssh(self, directory): """ Make directory safely over ssh or abort on failure Args: directory (str): The directory that will be created Returns: None """ try: ssh.remote_execute(self.dev_ip, ["mkdir", "-p", directory]) except subprocess32.CalledProcessError, err: common.log_subprocess32_error_and_abort(err)
def recovery_flash(self): """ Execute the flashing of device-side DFU-tools Aborts if the flashing fails Note that only one Edison should be powered on when doing the recovery flashing Returns: None """ logger.info("Recovery flashing.") try: # This can cause race condition if multiple devices are booted at # the same time! attempts = 0 xfstk_parameters = ["xfstk-dldr-solo", "--gpflags", "0x80000007", "--osimage", os.path.join( self._MODULE_DATA_PATH, "u-boot-edison.img"), "--fwdnx", os.path.join( self._MODULE_DATA_PATH, "edison_dnx_fwr.bin"), "--fwimage", os.path.join( self._MODULE_DATA_PATH, "edison_ifwi-dbg-00.bin"), "--osdnx", os.path.join( self._MODULE_DATA_PATH, "edison_dnx_osr.bin")] self._power_cycle() while subprocess32.call(xfstk_parameters) and attempts < 10: logger.info( "Rebooting and trying recovery flashing again. " + str(attempts)) self._power_cycle() time.sleep(random.randint(10, 30)) attempts += 1 except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err) except OSError as err: logger.critical("Failed recovery flashing, errno = " + str(err.errno) + ". Is the xFSTK tool installed?") sys.exit(1)
def recovery_flash(self): """ Execute the flashing of device-side DFU-tools Aborts if the flashing fails Note that only one Edison should be powered on when doing the recovery flashing Returns: None """ logging.info("Recovery flashing.") try: # This can cause race condition if multiple devices are booted at # the same time! attempts = 0 xfstk_parameters = ["xfstk-dldr-solo", "--gpflags", "0x80000007", "--osimage", os.path.join( self._MODULE_DATA_PATH, "u-boot-edison.img"), "--fwdnx", os.path.join( self._MODULE_DATA_PATH, "edison_dnx_fwr.bin"), "--fwimage", os.path.join( self._MODULE_DATA_PATH, "edison_ifwi-dbg-00.bin"), "--osdnx", os.path.join( self._MODULE_DATA_PATH, "edison_dnx_osr.bin")] self._power_cycle() while subprocess32.call(xfstk_parameters) and attempts < 10: logging.info( "Rebooting and trying recovery flashing again. " + str(attempts)) self._power_cycle() time.sleep(random.randint(10, 30)) attempts += 1 except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err) except OSError as err: logging.critical("Failed recovery flashing, errno = " + str(err.errno) + ". Is the xFSTK tool installed?") sys.exit(1)
def _mount(self, device_file): """ Mounts a directory over ssh into self.mount_dir Args: device_file (str): The device file that will be mounted Returns: None """ logging.info("Mounting " + device_file + " to " + self.mount_dir) try: ssh.remote_execute(self.dev_ip, ["mount", device_file, self.mount_dir]) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err)
def _unmount_local(self): """ Unmount the previously mounted image from class-defined folder Aborts if the unmount command fails Returns: None """ logger.info("Flushing and unmounting the root filesystem.") try: subprocess32.check_call(["sync"]) subprocess32.check_call(["umount", self._LOCAL_MOUNT_DIR]) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err)
def _mount(self, device_file): """ Mounts a directory over ssh into self.mount_dir Args: device_file (str): The device file that will be mounted Returns: None """ logging.info("Mounting " + device_file + " to " + self.mount_dir) try: ssh.remote_execute( self.dev_ip, ["mount", device_file, self.mount_dir]) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err)
def _change_ownership_over_ssh(self, file_name, uid, gid): """ Change file/directory ownership safely over ssh or abort on failure Args: file_name (str): The file which ownership is changed uid (integer): owner id gid (integer): group id Returns: None """ try: ssh.remote_execute( self.dev_ip, ["chown", str(uid) + ":" + str(gid), file_name]) except subprocess32.CalledProcessError, err: common.log_subprocess32_error_and_abort(err)
def _unmount_local(self): """ Unmount the previously mounted image from class-defined folder Aborts if the unmount command fails Returns: None """ logger.info("Flushing and unmounting the root filesystem.") try: subprocess32.check_call(["sync"]) subprocess32.check_call([ "guestunmount", os.path.join(os.curdir,self._LOCAL_MOUNT_DIR)]) except subprocess32.CalledProcessError as err: common.log_subprocess32_error_and_abort(err)