def _write_boot_partition(self): """ Erase old boot partition files and write the new ones Returns: None """ logging.info("Starting boot partition operations") logging.info("Creating DOS filesystem on " + self.parameters["boot_partition"]) ssh.remote_execute( self.dev_ip, [ "mkfs.fat", self.parameters["boot_partition"]]) self._mount(self.parameters["boot_partition"]) logging.info("Writing new boot partition") self._write_boot_partition_files() self._unmount_over_ssh()
def _write_root_partition(self): """ Erase old root partition files and write the new ones. Also adds public ssh key. Return: None """ logging.info("Starting root partition operations") logging.info("Creating ext4 filesystem on " + self.parameters["root_partition"]) ssh.remote_execute( self.dev_ip, [ "mkfs.ext4", self.parameters["root_partition"]]) self._mount(self.parameters["root_partition"]) logging.info("Writing new root partition") self._write_root_partition_files() self._add_ssh_key() self._unmount_over_ssh()
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 _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 _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 _mount_single_layer(self, image_file_name): """ Mount a hdddirect partition Returns: None """ logger.info("Mount one layer.") ssh.remote_execute(self.dev_ip, ["mount", self.get_root_partition_path(image_file_name), self._ROOT_PARTITION_MOUNT_POINT])
def _mount_single_layer(self, image_file_name): """ Mount a hdddirect partition Returns: None """ logger.info("Mount one layer.") ssh.remote_execute(self.dev_ip, [ "mount", self.get_root_partition_path(image_file_name), self._ROOT_PARTITION_MOUNT_POINT ])
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 verify_device_mode(ip, mode_name): """ Check that the device with given ip is responsive to ssh and is in the specified mode. The mode is checked by checking that the mode_name arg is present in the /proc/version file Args: ip (str): The device ip address mode_name (str): Word to check for in /proc/version Returns: True if the device is in the desired mode, False otherwise """ try: sshout = ssh.remote_execute(ip, ["cat", "/proc/version"]) if mode_name in sshout: logger.info("Found " + mode_name + " in DUT /proc/version") return True logger.info("Didn't find " + mode_name + " in DUT /proc/version") logger.debug("/cat/proc/version: " + str(sshout)) return False except subprocess32.CalledProcessError as err: logger.warning("Failed verifying the device mode with command: '" + str(err.cmd) + "' failed with error code: '" + str(err.returncode) + "' and output: '" + str(err.output) + "'.") return False
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 verify_device_mode(ip, mode): """ Check that the device with given ip is responsive to ssh and is in the specified mode. The mode is checked by checking that the mode arg is present in the /proc/version file Args: ip (str): The device ip address mode (str): The mode we want to check for Returns: True if the device is in the desired mode, False otherwise """ try: sshout = ssh.remote_execute(ip, ["cat", "/proc/version"]) if mode in sshout: logging.info("Found device in " + mode + " mode.") return True return False except subprocess32.CalledProcessError, err: logging.warning("Failed verifying the device mode with command: '" + str(err.cmd) + "' failed with error code: '" + str(err.returncode) + "' and output: '" + str(err.output) + "'.") return False
def verify_device_mode(ip, mode): """ Check that the device with given ip is responsive to ssh and is in the specified mode. The mode is checked by checking that the mode arg is present in the /proc/version file Args: ip (str): The device ip address mode (str): The mode we want to check for Returns: True if the device is in the desired mode, False otherwise """ try: sshout = ssh.remote_execute(ip, ["cat", "/proc/version"]) if mode in sshout: logging.info("Found device in " + mode + " mode.") return True return False except subprocess32.CalledProcessError, err: logging.warning( "Failed verifying the device mode with command: '" + str(err.cmd) + "' failed with error code: '" + str(err.returncode) + "' and output: '" + str(err.output) + "'.") return False
def verify_device_mode(ip, mode_name): """ Check that the device with given ip is responsive to ssh and is in the specified mode. The mode is checked by checking that the mode_name arg is present in the /proc/version file Args: ip (str): The device ip address mode_name (str): Word to check for in /proc/version Returns: True if the device is in the desired mode, False otherwise """ try: sshout = ssh.remote_execute(ip, ["cat", "/proc/version"]) if mode_name in sshout: logger.info("Found " + mode_name + " in DUT /proc/version") return True logger.info("Didn't find " + mode_name + " in DUT /proc/version") logger.debug("/cat/proc/version: " + str(sshout)) return False except subprocess32.CalledProcessError as err: logger.warning( "Failed verifying the device mode with command: '" + str(err.cmd) + "' failed with error code: '" + str(err.returncode) + "' and output: '" + str(err.output) + "'.") return False
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 find_root_partition(self): ''' Find _target_device partition that has /home/root ''' # Find all _target_device partitions partitions = [] target = self._target_device.split("/")[-1] lsblk = ssh.remote_execute(self.dev_ip, ["lsblk"]) lsblk = lsblk.split() for line in lsblk: if (target + "p") in line: line = ''.join(x for x in line if x.isalnum()) partitions.append(line) # Check through partitions if it contains '/home/root' directory for partition in partitions: ssh.remote_execute(self.dev_ip, ["mount", "/dev/" + partition, self._ROOT_PARTITION_MOUNT_POINT]) files = ssh.remote_execute(self.dev_ip, ["ls", self._ROOT_PARTITION_MOUNT_POINT]) if "home" in files: files = ssh.remote_execute(self.dev_ip, ["ls", self._ROOT_PARTITION_MOUNT_POINT + "home/"]) ssh.remote_execute(self.dev_ip, ["umount", self._ROOT_PARTITION_MOUNT_POINT]) if "root" in files: partition_path = "/dev/" + partition return partition_path raise errors.AFTDeviceError("Couldn't find root partition")
def find_root_partition(self): ''' Find _target_device partition that has /home/root ''' # Find all _target_device partitions partitions = [] target = self._target_device.split("/")[-1] lsblk = ssh.remote_execute(self.dev_ip, ["lsblk"]) lsblk = lsblk.split() for line in lsblk: if (target + "p") in line: line = ''.join(x for x in line if x.isalnum()) partitions.append(line) # Check through partitions if it contains '/home/root' directory for partition in partitions: ssh.remote_execute(self.dev_ip, [ "mount", "/dev/" + partition, self._ROOT_PARTITION_MOUNT_POINT ]) files = ssh.remote_execute( self.dev_ip, ["ls", self._ROOT_PARTITION_MOUNT_POINT]) if "home" in files: files = ssh.remote_execute( self.dev_ip, ["ls", self._ROOT_PARTITION_MOUNT_POINT + "home/"]) ssh.remote_execute(self.dev_ip, ["umount", self._ROOT_PARTITION_MOUNT_POINT]) if "root" in files: partition_path = "/dev/" + partition return partition_path raise errors.AFTDeviceError("Couldn't find root partition")
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 _write_boot_partition(self): """ Erase old boot partition files and write the new ones Returns: None """ logger.info("Starting boot partition operations") logger.info("Creating DOS filesystem on " + self.parameters["boot_partition"]) ssh.remote_execute(self.dev_ip, ["mkfs.fat", self.parameters["boot_partition"]]) self._mount(self.parameters["boot_partition"]) logger.info("Writing new boot partition") self._write_boot_partition_files() self._unmount_over_ssh()
def _write_root_partition(self): """ Erase old root partition files and write the new ones. Also adds public ssh key. Return: None """ logger.info("Starting root partition operations") logger.info("Creating ext4 filesystem on " + self.parameters["root_partition"]) ssh.remote_execute(self.dev_ip, ["mkfs.ext4", self.parameters["root_partition"]]) self._mount(self.parameters["root_partition"]) logger.info("Writing new root partition") self._write_root_partition_files() self._add_ssh_key() self._unmount_over_ssh()
def execute(self, command, timeout, user="******", verbose=False): """ Runs a command on the device and returns log and errorlevel. Args: command (str): The command that will be executed timeout (integer): Timeout for the command user (str): The user that executes the command verbose (boolean): Controls verbosity Return: Return value of aft.ssh.remote_execute """ return ssh.remote_execute(self.get_ip(), command, timeout=timeout, user=user)
def execute(self, command, timeout, user="******", verbose=False): """ Runs a command on the device and returns log and errorlevel. Args: command (str): The command that will be executed timeout (integer): Timeout for the command user (str): The user that executes the command verbose (boolean): Controls verbosity Return: Return value of aft.ssh.remote_execute """ return ssh.remote_execute( self.get_ip(), command, timeout=timeout, user=user)
def _mount_two_layers(self): """ Mount a hddimg which has 'rootfs' partition Returns: None """ logger.info("Mounts two layers.") ssh.remote_execute(self.dev_ip, ["modprobe", "vfat"]) # mount the first layer of .hddimg ssh.remote_execute(self.dev_ip, ["mount", self._target_device, self._SUPER_ROOT_MOUNT_POINT]) ssh.remote_execute(self.dev_ip, ["mount", self._SUPER_ROOT_MOUNT_POINT + "rootfs.img", self._ROOT_PARTITION_MOUNT_POINT])
def _mount_two_layers(self): """ Mount a hddimg which has 'rootfs' partition Returns: None """ logger.info("Mounts two layers.") ssh.remote_execute(self.dev_ip, ["modprobe", "vfat"]) # mount the first layer of .hddimg ssh.remote_execute( self.dev_ip, ["mount", self._target_device, self._SUPER_ROOT_MOUNT_POINT]) ssh.remote_execute(self.dev_ip, [ "mount", self._SUPER_ROOT_MOUNT_POINT + "rootfs.img", self._ROOT_PARTITION_MOUNT_POINT ])
def _install_tester_public_key(self, image_file_name): """ Copy ssh public key to root user on the target device. Returns: None """ # update info about the partition table if not self._uses_hddimg: self._mount_single_layer(image_file_name) else: self._mount_two_layers() # Identify the home of the root user root_user_home = ssh.remote_execute(self.dev_ip, [ "cat", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, "etc/passwd"), "|", "grep", "-e", '"^root"', "|", "sed", "-e", '"s/root:.*:root://"', "|", "sed", "-e", '"s/:.*//"' ]).rstrip().lstrip("/") # Ignore return value: directory might exist logger.info("Writing ssh-key to device.") ssh.remote_execute(self.dev_ip, [ "mkdir", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh") ], ignore_return_codes=[1]) ssh.remote_execute(self.dev_ip, [ "chmod", "700", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh") ]) ssh.remote_execute(self.dev_ip, [ "cat", "~/.ssh/authorized_keys", ">>", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh/authorized_keys") ]) ssh.remote_execute(self.dev_ip, [ "chmod", "600", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh/authorized_keys") ]) logger.info("Flushing.") ssh.remote_execute(self.dev_ip, ["sync"]) logger.info("Unmounting.") ssh.remote_execute(self.dev_ip, ["umount", self._ROOT_PARTITION_MOUNT_POINT]) if self._uses_hddimg: ssh.remote_execute(self.dev_ip, ["umount", self._SUPER_ROOT_MOUNT_POINT])
def _install_tester_public_key(self, image_file_name): """ Copy ssh public key to root user on the target device. Returns: None """ # update info about the partition table if not self._uses_hddimg: self._mount_single_layer(image_file_name) else: self._mount_two_layers() # Identify the home of the root user root_user_home = ssh.remote_execute( self.dev_ip, [ "cat", os.path.join( self._ROOT_PARTITION_MOUNT_POINT, "etc/passwd"), "|", "grep", "-e", '"^root"', "|", "sed", "-e", '"s/root:.*:root://"', "|", "sed", "-e", '"s/:.*//"']).rstrip().lstrip("/") # Ignore return value: directory might exist logger.info("Writing ssh-key to device.") ssh.remote_execute( self.dev_ip, [ "mkdir", os.path.join( self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh") ], ignore_return_codes=[1]) ssh.remote_execute( self.dev_ip, [ "chmod", "700", os.path.join( self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh") ]) ssh.remote_execute( self.dev_ip, [ "cat", "~/.ssh/authorized_keys", ">>", os.path.join( self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh/authorized_keys")]) ssh.remote_execute( self.dev_ip, [ "chmod", "600", os.path.join( self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh/authorized_keys") ]) logger.info("Flushing.") ssh.remote_execute(self.dev_ip, ["sync"]) logger.info("Unmounting.") ssh.remote_execute( self.dev_ip, ["umount", self._ROOT_PARTITION_MOUNT_POINT]) if self._uses_hddimg: ssh.remote_execute( self.dev_ip, ["umount", self._SUPER_ROOT_MOUNT_POINT])
def _remove_temp_dir(self): """ Remove the temp directory used during flashing """ ssh.remote_execute(self.dev_ip, ["rm", "-r", self.working_directory])
def _install_tester_public_key(self, image_file_name): """ Copy ssh public key to root user on the target device. Returns: None """ # update info about the partition table if not self._uses_hddimg: self._mount_single_layer(image_file_name) else: self._mount_two_layers() # Identify the home of the root user root_user_home = ssh.remote_execute(self.dev_ip, [ "cat", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, "etc/passwd"), "|", "grep", "-e", '"^root"', "|", "sed", "-e", '"s/root:.*:root://"', "|", "sed", "-e", '"s/:.*//"' ]).rstrip().lstrip("/") # Ignore return value: directory might exist logger.info("Writing ssh-key to device.") ssh.remote_execute(self.dev_ip, [ "mkdir", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh") ], ignore_return_codes=[1]) ssh.remote_execute(self.dev_ip, [ "chmod", "700", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh") ]) # Try to copy SSH keys to the authorized_keys file try: ssh.remote_execute(self.dev_ip, [ "cat", "~/.ssh/authorized_keys", ">>", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh/authorized_keys") ]) ssh.remote_execute(self.dev_ip, [ "chmod", "600", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, root_user_home, ".ssh/authorized_keys") ]) # If the preceding method fails, try to copy them directly to a dropbear authorized_keys files (as the the preceding method fails if the device is running # dropbear instead of OpenSSH) except: logger.info( "Failed, trying to write the ssh-key in dropbear file instead." ) ssh.remote_execute(self.dev_ip, [ "cat", "~/.ssh/authorized_keys", ">>", os.path.join(self._ROOT_PARTITION_MOUNT_POINT, "var/lib/dropbear/authorized_keys") ]) logger.info("Success.") logger.info("Flushing.") ssh.remote_execute(self.dev_ip, ["sync"]) logger.info("Unmounting.") ssh.remote_execute(self.dev_ip, ["umount", self._ROOT_PARTITION_MOUNT_POINT]) if self._uses_hddimg: ssh.remote_execute(self.dev_ip, ["umount", self._SUPER_ROOT_MOUNT_POINT])
def _flash_image(self, nfs_file_name, filename): """ Writes image into the internal storage of the device. Args: nfs_file_name (str): The image file path on the nfs filename (str): The image filename Returns: None """ logger.info("Mounting the nfs containing the image to flash.") ssh.remote_execute(self.dev_ip, ["mount", self._IMG_NFS_MOUNT_POINT], ignore_return_codes=[32]) logger.info("Writing " + str(nfs_file_name) + " to internal storage.") bmap_args = ["bmaptool", "copy", nfs_file_name, self._target_device] if os.path.isfile(filename + ".bmap"): logger.info("Found "+ filename +".bmap. Using bmap for flashing.") else: logger.info("Didn't find " + filename + ".bmap. Flashing without it.") bmap_args.insert(2, "--nobmap") ssh.remote_execute(self.dev_ip, bmap_args, timeout=self._SSH_IMAGE_WRITING_TIMEOUT) # Flashing the same file as already on the disk causes non-blocking # removal and re-creation of /dev/disk/by-partuuid/ files. This sequence # either delays enough or actually settles it. logger.info("Partprobing.") ssh.remote_execute(self.dev_ip, ["partprobe", self._target_device]) ssh.remote_execute(self.dev_ip, ["sync"]) ssh.remote_execute(self.dev_ip, ["udevadm", "trigger"]) ssh.remote_execute(self.dev_ip, ["udevadm", "settle"]) ssh.remote_execute(self.dev_ip, ["udevadm", "control", "-S"])
def _flash_image(self, nfs_file_name, filename): """ Writes image into the internal storage of the device. Args: nfs_file_name (str): The image file path on the nfs filename (str): The image filename Returns: None """ logger.info("Mounting the nfs containing the image to flash.") ssh.remote_execute(self.dev_ip, ["mount", self._IMG_NFS_MOUNT_POINT], ignore_return_codes=[32]) logger.info("Writing " + str(nfs_file_name) + " to internal storage.") bmap_args = ["bmaptool", "copy", nfs_file_name, self._target_device] if os.path.isfile(filename + ".bmap"): logger.info("Found " + filename + ".bmap. Using bmap for flashing.") else: logger.info("Didn't find " + filename + ".bmap. Flashing without it.") bmap_args.insert(2, "--nobmap") ssh.remote_execute(self.dev_ip, bmap_args, timeout=self._SSH_IMAGE_WRITING_TIMEOUT) # Flashing the same file as already on the disk causes non-blocking # removal and re-creation of /dev/disk/by-partuuid/ files. This sequence # either delays enough or actually settles it. logger.info("Partprobing.") ssh.remote_execute(self.dev_ip, ["partprobe", self._target_device]) ssh.remote_execute(self.dev_ip, ["sync"]) ssh.remote_execute(self.dev_ip, ["udevadm", "trigger"]) ssh.remote_execute(self.dev_ip, ["udevadm", "settle"]) ssh.remote_execute(self.dev_ip, ["udevadm", "control", "-S"])