Ejemplo n.º 1
0
    def __init__(self, device):
        self._device = device
        self.test_cases = []
        self._results = []
        self._start_time = None
        self._end_time = None

        test_plan_name = device.test_plan
        test_plan_file = os.path.join("/etc/aft/test_plan/",
                                      device.test_plan + ".cfg")
        test_plan_config = ConfigParser.SafeConfigParser()
        test_plan_config.read(test_plan_file)

        if len(test_plan_config.sections()) == 0:
            raise errors.AFTConfigurationError(
                "Test plan " + str(test_plan_name) + " (" +
                str(test_plan_file) + ") doesn't " +
                "have any test cases. Does the file exist?")

        for test_case_name in test_plan_config.sections():
            test_case_config = dict(test_plan_config.items(test_case_name))
            test_case_config["name"] = test_case_name
            test_case = aft.testcasefactory.build_test_case(test_case_config)
            self.test_cases.append(test_case)

        logger.info("Built test plan with " + str(len(self.test_cases)) +
                    " test cases.")
Ejemplo n.º 2
0
    def _enter_test_mode(self):
        """
        Enter test mode by booting from sd card

        Returns:
            None

        Raises:
            aft.errors.AFTDeviceError if the device failed to enter the test
            mode
        """
        # device by default boots from sd card, so if everything has gone well,
        # we can just power cycle to boot the testable image
        logger.info("Entering test mode")
        for _ in range(self._TEST_MODE_RETRY_ATTEMPTS):
            try:
                self._power_cycle()
                self.dev_ip = self._wait_for_responsive_ip()

                if self.dev_ip and self._verify_mode(
                        self.parameters["test_mode"]):
                    return
                else:
                    logger.warning("Failed to enter test mode")

            except KeyboardInterrupt:
                raise

            except:
                _err = sys.exc_info()
                logger.error(str(_err[0]).split("'")[1] + ": " + str(_err[1]))

        raise errors.AFTDeviceError("Could not set the device in test mode")
Ejemplo n.º 3
0
    def get_root_partition_path(self, image_file_name):
        """
        Select either the default config value to be the root_partition
        or if the disk layout file exists, use the rootfs from it.

        Args:
            image_file_name (str): The name of the image file. Disk layout file
            name is based on this

        Returns:
            (str): path to the disk pseudo file
        """
        layout_file_name = self.get_layout_file_name(image_file_name)

        if not os.path.isfile(layout_file_name):
            logger.info("Disk layout file " + layout_file_name  +
                         " doesn't exist. Finding root partition.")
            return self.find_root_partition()

        layout_file = open(layout_file_name, "r")
        disk_layout = json.load(layout_file)
        rootfs_partition = next(
            partition for partition in list(disk_layout.values()) \
            if isinstance(partition, dict) and \
            partition["name"] == "rootfs")
        return os.path.join(
            "/dev",
            "disk",
            "by-partuuid",
            rootfs_partition["uuid"])
Ejemplo n.º 4
0
    def get_root_partition_path(self, image_file_name):
        """
        Select either the default config value to be the root_partition
        or if the disk layout file exists, use the rootfs from it.

        Args:
            image_file_name (str): The name of the image file. Disk layout file
            name is based on this

        Returns:
            (str): path to the disk pseudo file
        """
        layout_file_name = self.get_layout_file_name(image_file_name)

        if not os.path.isfile(layout_file_name):
            logger.info("Disk layout file " + layout_file_name +
                        " doesn't exist. Finding root partition.")
            return self.find_root_partition()

        layout_file = open(layout_file_name, "r")
        disk_layout = json.load(layout_file)
        rootfs_partition = next(
            partition for partition in list(disk_layout.values()) \
            if isinstance(partition, dict) and \
            partition["name"] == "rootfs")
        return os.path.join("/dev", "disk", "by-partuuid",
                            rootfs_partition["uuid"])
Ejemplo n.º 5
0
    def _find_active_serial_ports_from(self, wait_duration, device_files):
        """
        Find and returns list of active USB serial ports.

        This spawns a process that actually does the work.

        Args:
            device_files (list of strings):
                List of device files that will be checked for serial ports.
                Note that any other device file than ttyUSBx will be ignored.

        Returns:
            List of device files that have active serial port.
            Example: ["ttyUSB2", "ttyUSB4", "ttyUSB7"]

        """
        serial_results = Queue()

        serial_finder = Process(
            target=TopologyBuilder._get_active_serial_device_files,
            args=(self, serial_results, wait_duration, device_files))
        if self._verbose:
            print("Serial thread - Finding active serial ports")

        logger.info("Finding active serial ports")
        serial_finder.start()

        return serial_results
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
    def _create_configuration(self):
        """
        Create and return ConfigParser object containing the device
        configurations

        Return:
            ConfigParser object containing the configurations
        """
        logger.info("Creating configuration object")
        config = SafeConfigParser()

        device_ids = {}

        for device in self._devices:
            # lack of model generally means that there was an unused power
            # cutter socket
            if not "model" in device:
                continue

            if not device["model"] in device_ids:
                device_ids[device["model"]] = 1

            dev_id = device_ids[device["model"]]
            device_ids[device["model"]] = dev_id + 1

            section = device["model"].upper() + "_" + str(dev_id)

            config.add_section(section)

            for key in device:
                config.set(section, key, str(device[key]))

        return config
Ejemplo n.º 8
0
    def _find_active_serial_ports_from(self, wait_duration, device_files):
        """
        Find and returns list of active USB serial ports.

        This spawns a process that actually does the work.

        Args:
            device_files (list of strings):
                List of device files that will be checked for serial ports.
                Note that any other device file than ttyUSBx will be ignored.

        Returns:
            List of device files that have active serial port.
            Example: ["ttyUSB2", "ttyUSB4", "ttyUSB7"]

        """
        serial_results = Queue()

        serial_finder = Process(
            target=TopologyBuilder._get_active_serial_device_files,
            args=(self, serial_results, wait_duration, device_files),
        )
        if self._verbose:
            print("Serial thread - Finding active serial ports")

        logger.info("Finding active serial ports")
        serial_finder.start()

        return serial_results
Ejemplo n.º 9
0
    def _remove_blacklisted_devices(self, devices):
        """
        Remove blacklisted devices from the device list

        Args:
            List of devices

        Returns:
            Filtered list of devices
        """
        _device_blacklist = self._construct_blacklist()

        filtered_devices = []

        for device in devices:
            for blacklisted_device in _device_blacklist:
                if blacklisted_device["id"] == device.dev_id:
                    msg = ("Removed blacklisted device " +
                            blacklisted_device["name"] + " from device pool " +
                            "(Reason: " + blacklisted_device["reason"] + ")")

                    logger.info(msg)
                    print(msg)
                    break
            else: # else clause for the for loop
                filtered_devices.append(device)

        return filtered_devices
Ejemplo n.º 10
0
    def write_image(self, file_name):
        """
        Writes the new image into the Edison

        Args:
            file_name (str):
                The file name of the image that will be flashed on the device
        Returns:
            True

        Raises:
            aft.errors.AFTDeviceError on various failures
            aft.errors.AFTConnectionError if the ssh connection could not be
                formed

        """

        file_name_no_extension = os.path.splitext(file_name)[0]

        self._mount_local(file_name_no_extension)
        self._add_usb_networking()
        self._add_ssh_key()
        self._unmount_local()

        # self._flashing_attempts = 0 # dfu-util may occasionally fail. Extra
        # attempts could be used?
        logger.info("Executing flashing sequence.")
        return self._flash_image(file_name_no_extension)
Ejemplo n.º 11
0
    def _enter_test_mode(self):
        """
        Enter test mode by booting from sd card

        Returns:
            None

        Raises:
            aft.errors.AFTDeviceError if the device failed to enter the test
            mode
        """
        # device by default boots from sd card, so if everything has gone well,
        # we can just power cycle to boot the testable image
        logger.info("Entering test mode")
        for _ in range(self._TEST_MODE_RETRY_ATTEMPTS):
            self._power_cycle()
            self.dev_ip = self._wait_for_responsive_ip()


            if self.dev_ip and self._verify_mode(self.parameters["test_mode"]):
                return
            else:
                logger.warning("Failed to enter test mode")

        raise errors.AFTDeviceError("Could not set the device in test mode")
Ejemplo n.º 12
0
    def _stop_vm(self):
        if not self._is_powered_on:
            return

        logger.info("Stopping the vm")
        misc.local_execute((
            "VBoxManage controlvm " + self._vm_name + " poweroff").split())
Ejemplo n.º 13
0
    def _create_configuration(self):
        """
        Create and return ConfigParser object containing the device
        configurations

        Return:
            ConfigParser object containing the configurations
        """
        logger.info("Creating configuration object")
        config = SafeConfigParser()

        device_ids = {}

        for device in self._devices:
            # lack of model generally means that there was an unused power
            # cutter socket
            if not "model" in device:
                continue

            if not device["model"] in device_ids:
                device_ids[device["model"]] = 1

            dev_id = device_ids[device["model"]]
            device_ids[device["model"]] = dev_id + 1

            section = device["model"].upper() + "_" + str(dev_id)

            config.add_section(section)

            for key in device:
                config.set(section, key, str(device[key]))

        return config
Ejemplo n.º 14
0
 def run_remote_command(self, device):
     """
     Executes a command remotely, on the device.
     """
     self.output = device.execute(self.parameters.split(), timeout=120)
     logger.info("Command: " + str(self.parameters) + "\nresult: " + str(self.output) + ".")
     return self._check_for_success()
Ejemplo n.º 15
0
    def _set_device_pem_port(self, device, pem_results):
        """
        Check if any PEM port has stopped responding, and if so, associate it
        with the device.

        Args:
            device (dictionary): The device dictionary that is used to store
                                 device information.

            pem_results (multiprocessing.Queue): Queue containing list of active
                                                 PEM device files.
        """
        logger.info("Configuring device PEM settings")
        active_pem_ports = pem_results.get()

        dead_ports = list(set(self._pem_ports).difference(active_pem_ports))
        if len(dead_ports) > 1:
            if self._verbose:
                print("Too many usb devices disappeared - cannot configure PEM" "port")
            logger.warning("Too many usb devices disappeared - cannot " + "configure PEM port")
            logger.warning("Device dictionary: " + str(device))

        elif len(dead_ports) == 0:
            if self._verbose:
                print("All USB devices still active - device seems to not to " "use PEM")
        else:
            if self._verbose:
                print("PEM port " + dead_ports[0] + " disappeared")

            device["pem_port"] = "/dev/" + dead_ports[0]
            # At the time of writing this, PEM only supports serial connection.
            device["pem_interface"] = "serialconnection"
            self._pem_ports.remove(dead_ports[0])
Ejemplo n.º 16
0
Archivo: ssh.py Proyecto: Valtis/AFT
def remote_execute(remote_ip, command, timeout = 60, ignore_return_codes = None,
                   user = "******", connect_timeout = 15):
    """
    Execute a Bash command over ssh on a remote device with IP 'remote_ip'.
    Returns combines stdout and stderr if there are no errors. On error raises
    subprocess32 errors.
    """

    ssh_args = ["ssh",
                "-i", "".join([os.path.expanduser("~"), "/.ssh/id_rsa_testing_harness"]),
                "-o", "UserKnownHostsFile=/dev/null",
                "-o", "StrictHostKeyChecking=no",
                "-o", "BatchMode=yes",
                "-o", "LogLevel=ERROR",
                "-o", "ConnectTimeout=" + str(connect_timeout),
                user + "@" + str(remote_ip),
                _get_proxy_settings(),]

    logger.info("Executing " + " ".join(command), filename="ssh.log")

    ret = ""
    try:
        ret = tools.local_execute(ssh_args + command, timeout, ignore_return_codes)
    except subprocess32.CalledProcessError as err:
        logger.error("Command raised exception: " + str(err), filename="ssh.log")
        logger.error("Output: " + str(err.output), filename="ssh.log")
        raise err

    return ret
Ejemplo n.º 17
0
    def check_poweron(self):
        """
        Checks if device powers on sucessfully by checking if it enters DFU mode
        correctly


        Returns:
            None

        Raises:
            aft.errors.AFTDeviceError on failure to connect to the device after
            running out of retries

            aft.errors.AFTConfigurationError if for some reason all retries fail
            and no other exception is raised
        """
        attempts = 3
        exception = None
        for i in range(attempts):
            logger.info("Attempt " + str(i + 1) + " of " + str(attempts) +
                        " to power on the device " +
                        self._configuration["name"])
            try:
                self._power_cycle()
                self._wait_for_device()
            except errors.AFTDeviceError as error:
                exception = error
                pass
            else:
                return

        if exception:
            raise exception

        raise errors.AFTConfigurationError("Failed to power on the device")
Ejemplo n.º 18
0
    def open_interface(self):
        """
        Open the host's network interface for testing

        Returns:
            None
        """
        interface = self._get_usb_nic()
        ip_subnet = self._host_ip + "/30"
        logger.info("Opening the host network interface for testing.")

        # The ifconfig command requires root privileges to run, and in general
        # we would like to run AFT without root privileges. However, we can add
        # a shell script to the sudoers file, which allows us to invoke it with
        # sudo, without the whole program requiring sudo. Hence, the below commands
        # will succeed even without root privileges

        # Note: Assumes that this file is under aft/devices, and that the shell
        # script is under aft/tools
        interface_script = os.path.join(os.path.dirname(__file__),
                                        os.path.pardir, "tools",
                                        "interface_script.sh")
        subprocess32.check_call(["sudo", interface_script, interface, "up"])
        subprocess32.check_call(
            ["sudo", interface_script, interface, ip_subnet])
Ejemplo n.º 19
0
    def write_image(self, file_name):
        """
        Writes the new image into the Edison

        Args:
            file_name (str):
                The file name of the image that will be flashed on the device
        Returns:
            True

        Raises:
            aft.errors.AFTDeviceError on various failures
            aft.errors.AFTConnectionError if the ssh connection could not be
                formed

        """

        file_name_no_extension = os.path.splitext(file_name)[0]

        self._mount_local(file_name_no_extension)
        self._add_usb_networking()
        self._add_ssh_key()
        self._unmount_local()

        # self._flashing_attempts = 0 # dfu-util may occasionally fail. Extra
        # attempts could be used?
        logger.info("Executing flashing sequence.")
        return self._flash_image(file_name_no_extension)
Ejemplo n.º 20
0
    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)
Ejemplo n.º 21
0
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
Ejemplo n.º 22
0
    def _set_device_serial_port(self, device, serial_results):
        """
        Checks if any serial port has stopped responding, and if so, associates
        it with the device.

        Args:
            device (dictionary): The device dictionary that is used to store
                                 device information.

            serial_results (multiprocessing.Queue): Queue containing list of
                                                    active serial device files.
        """
        logger.info("Configuring device serial settings")
        active_serial_ports = serial_results.get()

        dead_ports = list(
            set(self._serial_ports).difference(active_serial_ports))

        if len(dead_ports) > 1:
            if self._verbose:
                print("Too many usb devices disappeared - cannot configure "
                      "serial port")
            logger.warning("Too many usb devices disappeared - cannot " +
                           "configure serial port")
            logger.warning("Device dictionary: " + str(device))
        elif len(dead_ports) == 0:
            if self._verbose:
                print("All USB devices still active - device seems to not to "
                      "use serial port")
        else:
            if self._verbose:
                print("Serial port " + dead_ports[0] + " disappeared")
            device["serial_port"] = "/dev/" + dead_ports[0]
            device["serial_bauds"] = 115200
            self._serial_ports.remove(dead_ports[0])
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
    def _set_device_serial_port(self, device, serial_results):
        """
        Checks if any serial port has stopped responding, and if so, associates
        it with the device.

        Args:
            device (dictionary): The device dictionary that is used to store
                                 device information.

            serial_results (multiprocessing.Queue): Queue containing list of
                                                    active serial device files.
        """
        logger.info("Configuring device serial settings")
        active_serial_ports = serial_results.get()

        dead_ports = list(set(self._serial_ports).difference(active_serial_ports))

        if len(dead_ports) > 1:
            if self._verbose:
                print("Too many usb devices disappeared - cannot configure " "serial port")
            logger.warning("Too many usb devices disappeared - cannot " + "configure serial port")
            logger.warning("Device dictionary: " + str(device))
        elif len(dead_ports) == 0:
            if self._verbose:
                print("All USB devices still active - device seems to not to " "use serial port")
        else:
            if self._verbose:
                print("Serial port " + dead_ports[0] + " disappeared")
            device["serial_port"] = "/dev/" + dead_ports[0]
            device["serial_bauds"] = 115200
            self._serial_ports.remove(dead_ports[0])
Ejemplo n.º 25
0
    def check_poweron(self):
        """
        Checks if device powers on sucessfully by checking if it enters DFU mode
        correctly


        Returns:
            None

        Raises:
            aft.errors.AFTDeviceError on failure to connect to the device after
            running out of retries

            aft.errors.AFTConfigurationError if for some reason all retries fail
            and no other exception is raised
        """
        attempts = 3
        exception = None
        for i in range(attempts):
            logger.info("Attempt " + str(i + 1) + " of " + str(attempts) +
                " to power on the device " + self._configuration["name"])
            try:
                self._power_cycle()
                self._wait_for_device()
            except errors.AFTDeviceError as error:
                exception = error
                pass
            else:
                return

        if exception:
            raise exception


        raise errors.AFTConfigurationError("Failed to power on the device")
Ejemplo n.º 26
0
    def _get_device_configuration(self, cutter):
        """
        Disconnects a cutter, then checks if any ip, serial port or PEM has
        stopped responding. These will then be associated with each other.

        Args:
            cutter (aft.Cutter): The cutter that will be disconnected


        Returns:
            Dictionary containing all the associated information (ports, cutters
            etc). This varies depending on actual device type and physical
            connections. Edisons for example use USB networking and have
            different attributes present as a result.

            Example dictionary (content can and will vary):
            {
                "model": "MinnowboardMAX"
                "id": "12:34:56:78:90:ab",
                "cutter": "123456",
                "channel": "4",
                "pem_interface": "serialconnection",
                "pem_port": "/dev/ttyUSB9",
                "serial_port" = "/dev/ttyUSB2",
                "serial_bauds": "115200"
            }

        """

        logger.info("Shutting down a cutter")
        if self._verbose:
            print("Disconnected cutter")
            pprint.pprint(cutter.get_cutter_config())
            print("")
            print("Pinging addresses and checking ports for dead ones")

        cutter.disconnect()

        # start the threads as soon as possible so that their results are
        # available as soon as possible
        wait_duration = 30
        pem_results = self._find_active_pem_ports_from(wait_duration, self._pem_ports)

        serial_results = self._find_active_serial_ports_from(wait_duration, self._serial_ports)

        device = {}

        self._set_device_cutter_config(device, cutter)
        self._set_device_network_and_type(device)
        self._set_device_serial_port(device, serial_results)
        self._set_device_pem_port(device, pem_results)

        if self._verbose:
            print("Created device configuration:")
            print("")
            pprint.pprint(device)
            print("")

        return device
Ejemplo n.º 27
0
def check(args):
    """
    Checks that the specified device is configured correctly

    Args:
        args (configuration object): Program command line arguments

    Returns:
        Tuple (Bool, String): Test status code and result message string. True
        indicates tests passed succesfully, false indicates that there were
        failures
    """

    if not args.device:
        raise errors.AFTConfigurationError(
            "You must specify the device that will be checked")

    if args.verbose:
        print("Running configuration check on " + args.device)

    if args.checkall:
        logger.init_thread(args.device + "_")

    logger.info("Running configuration check on " + args.device)

    manager = DevicesManager(args)
    device = manager.reserve_specific(args.device)

    if args.verbose:
        print("Device " + args.device + " acquired, running checks")

    try:
        sanity_results = _run_sanity_tests(args, device)
        image_test_results = (True, "Image Test result: Not run")
        # only run image test if sanity test passed
        if sanity_results[0] == True:
            image_test_results = _run_tests_on_know_good_image(args, device)

    finally:
        if args.verbose:
            print("Releasing device " + args.device)

        if not args.nopoweroff:
            device.detach()

        manager.release(device)

    results = (sanity_results[0] and image_test_results[0],
               sanity_results[1] + "\n" + image_test_results[1])

    if not results[0]:
        common.blacklist_device(device.dev_id, args.device,
                                "Failed device health check")
        msg = "Device " + args.device + " failed health test - blacklisting"
        logger.info(msg)
        if args.verbose:
            print msg

    return results
Ejemplo n.º 28
0
Archivo: device.py Proyecto: dl9pf/DAFT
 def _power_cycle(self):
     """
     Reboot the device.
     """
     logger.info("Rebooting the device.")
     self.detach()
     sleep(self._POWER_CYCLE_DELAY)
     self.attach()
Ejemplo n.º 29
0
 def _power_cycle(self):
     """
     Reboot the device.
     """
     logger.info("Rebooting the device.")
     self.detach()
     sleep(self._POWER_CYCLE_DELAY)
     self.attach()
Ejemplo n.º 30
0
 def stop_image_usb_emulation(self, leases_file):
     """
     Stop using the image with USB mass storage emulation
     """
     self.free_dnsmasq_leases(leases_file)
     local_execute("stop_libcomposite".split())
     local_execute("systemctl start libcomposite.service".split())
     logger.info("Stopped USB mass storage emulation with an image")
Ejemplo n.º 31
0
    def send_a_key(self, key, timeout=20):
        '''
        HID keyboard message length is 8 bytes and format is:

            [modifier, reserved, Key1, Key2, Key3, Key4, Key6, Key7]

        So first byte is for modifier key and all bytes after third one are for
        normal keys. After sending a key stroke, empty message with zeroes has
        to be sent to stop the key being pressed. Messages are sent by writing
        to the emulated HID usb port in /dev/. US HID keyboard hex codes
        are used for translating keys.

        Args:
            key: A key to send, for example: "a", "z", "3", "F2", "ENTER"
            timeout: how long sending a key will be tried until quitting [s]
        '''
        def writer(path, message, empty):
            while True:
                try:
                    with open(path, "w") as emulator:
                        emulator.write(message.decode())  # Send the key
                        emulator.write(empty)  # Stop the key being pressed
                except IOError:
                    sleep(1)
                else:
                    return 0

        # Empty message which will be sent to stop any keys being pressed
        empty = "\x00\x00\x00\x00\x00\x00\x00\x00"
        usb_message = bytearray(empty.encode())  # Initialize usb message
        hex_key, _modifier = self.key_to_hex(key)  # Translate key to hex code

        # Override self.modifier if the key needs a specific one
        if _modifier:
            modifier = _modifier
        else:
            modifier = self.modifier

        usb_message[2] = hex_key
        usb_message[0] = modifier

        # Do the writing in a subprocess as it hangs in some rare cases
        writer = Process(target=writer,
                         args=(self.emulator, usb_message, empty))
        writer.start()
        writer.join(20)
        if writer.is_alive():
            writer.terminate()
            msg = "Keyboard emulator couldn't connect to host or it froze"
            logger.error(msg, "kb_emulator.log")
            raise TimeoutError(msg)

        logger.info(
            "Sent key: " + key.ljust(5) + "  hex code: " +
            format(hex_key, '#04x') + "  modifier: " +
            format(modifier, '#04x'), "kb_emulator.log")
        return 0
Ejemplo n.º 32
0
 def _result_has_zero_fails(self):
     """
     Test if there are FAILED test cases in the QA-test case output
     """
     logger.info(self.output)
     failed_matches = re.findall("FAILED", self.output)
     result = True
     if len(failed_matches) > 0:
         result = False
     return result
Ejemplo n.º 33
0
 def _result_has_zero_fails(self):
     """
     Test if there are FAILED test cases in the QA-test case output
     """
     logger.info(self.output)
     failed_matches = re.findall("FAILED", self.output)
     result = True
     if len(failed_matches) > 0:
         result = False
     return result
Ejemplo n.º 34
0
 def _save_test_results(self):
     """
     Store the test results.
     """
     logger.info("Storing the test results.")
     xunit_results = self._results_to_xunit()
     results_filename = self.get_results_location()
     with open(results_filename, "w") as results_file:
         results_file.write(xunit_results)
     logger.info("Results saved to " + str(results_filename) + ".")
Ejemplo n.º 35
0
 def _save_test_results(self):
     """
     Store the test results.
     """
     logger.info("Storing the test results.")
     xunit_results = self._results_to_xunit()
     results_filename = self.get_results_location()
     with open(results_filename, "w") as results_file:
         results_file.write(xunit_results)
     logger.info("Results saved to " + str(results_filename) + ".")
Ejemplo n.º 36
0
    def send_a_key(self, key, timeout=20):
        '''
        HID keyboard message length is 8 bytes and format is:

            [modifier, reserved, Key1, Key2, Key3, Key4, Key6, Key7]

        So first byte is for modifier key and all bytes after third one are for
        normal keys. After sending a key stroke, empty message with zeroes has
        to be sent to stop the key being pressed. Messages are sent by writing
        to the emulated HID usb port in /dev/. US HID keyboard hex codes
        are used for translating keys.

        Args:
            key: A key to send, for example: "a", "z", "3", "F2", "ENTER"
            timeout: how long sending a key will be tried until quitting [s]
        '''
        def writer(path, message, empty):
            while True:
                try:
                    with open(path, "w") as emulator:
                        emulator.write(message.decode()) # Send the key
                        emulator.write(empty) # Stop the key being pressed
                except IOError:
                    sleep(1)
                else:
                    return 0

        # Empty message which will be sent to stop any keys being pressed
        empty = "\x00\x00\x00\x00\x00\x00\x00\x00"
        usb_message = bytearray(empty.encode()) # Initialize usb message
        hex_key, _modifier = self.key_to_hex(key) # Translate key to hex code

        # Override self.modifier if the key needs a specific one
        if _modifier:
            modifier = _modifier
        else:
            modifier = self.modifier

        usb_message[2] = hex_key
        usb_message[0] = modifier

        # Do the writing in a subprocess as it hangs in some rare cases
        writer = Process(target=writer, args=(self.emulator, usb_message, empty))
        writer.start()
        writer.join(20)
        if writer.is_alive():
            writer.terminate()
            msg = "Keyboard emulator couldn't connect to host or it froze"
            logger.error(msg, "kb_emulator.log")
            raise TimeoutError(msg)

        logger.info("Sent key: " + key.ljust(5) + "  hex code: " +
                    format(hex_key, '#04x') + "  modifier: " +
                    format(modifier, '#04x'), "kb_emulator.log")
        return 0
Ejemplo n.º 37
0
    def _enter_mode(self, mode):
        """
        Try to put the device into the specified mode.

        Args:
            mode (Dictionary):
                Dictionary that contains the mode specific information

        Returns:
            None

        Raises:
            aft.errors.AFTDeviceError if device fails to enter the mode or if
            keyboard emulator fails to connect
        """
        # Sometimes booting to a mode fails.
        logger.info("Trying to enter " + mode["name"] + " mode up to " +
                    str(self._RETRY_ATTEMPTS) + " times.")

        for _ in range(self._RETRY_ATTEMPTS):
            try:
                self._power_cycle()

                if self.kb_emulator:
                    logger.info("Using " + type(self.kb_emulator).__name__ +
                                " to send keyboard sequence " +
                                mode["sequence"])

                    self.kb_emulator.send_keystrokes(mode["sequence"])

                else:
                    logger.warning(
                        "No keyboard emulator defined for the device")

                ip_address = self._wait_for_responsive_ip()

                if ip_address:
                    if self._verify_mode(mode["name"]):
                        return
                else:
                    logger.warning("Failed entering " + mode["name"] +
                                   " mode.")

            except KeyboardInterrupt:
                raise

            except:
                _err = sys.exc_info()
                logger.error(str(_err[0]).split("'")[1] + ": " + str(_err[1]))

        logger.critical("Unable to get the device in mode " + mode["name"])

        raise errors.AFTDeviceError("Could not set the device in mode " +
                                    mode["name"])
Ejemplo n.º 38
0
    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)
Ejemplo n.º 39
0
    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)
Ejemplo n.º 40
0
 def free_dnsmasq_leases(self, leases_file):
     """
     dnsmasq.leases file needs to be cleared and dnsmasq.service restarted
     or there will be no IP address to give for DUT if same
     image is used in quick succession with and without --emulateusb
     """
     local_execute("systemctl stop dnsmasq.service".split())
     with open(leases_file, "w") as f:
         f.write("")
         f.flush()
     local_execute("systemctl start dnsmasq.service".split())
     logger.info("Freed dnsmasq leases")
Ejemplo n.º 41
0
    def _do_import_vm(self, ova_appliance):
        """
        Import the .ova appliance and grab the virtual hard drive name and VM
        name

        Args:
            ova_appliance (str):
                The ova appliance file

        Returns:
            None

        Raises:
            aft.errors.AFTDeviceError:
                If hard drive name or vm name were not set
        """

        output = misc.local_execute(
            ("VBoxManage import " + ova_appliance + "").split())

        # Get virtual hard drive name and VM name from output
        output = output.split("\n")
        for line in output:
            # Get hard drive name
            if "Hard disk image" in line:
                hdd_path_portion = line.split()[7].split("=")
                if hdd_path_portion[0] != "path":
                    break

                self._vhdd = hdd_path_portion[1]

                if self._vhdd.endswith(","):
                    self._vhdd = self._vhdd[:-1]

            # get VM name
            if "Suggested VM name" in line:
                self._vm_name = line.split()[4]

                # Strip starting ", if present
                if self._vm_name.startswith('"'):
                    self._vm_name = self._vm_name[1:]
                # Strip ending ", if present
                if self._vm_name.endswith('"'):
                    self._vm_name = self._vm_name[:-1]

        if self._vhdd and self._vm_name:
            logger.info("VM name: " + self._vm_name)
            logger.info("VHDD name: " + self._vhdd)
            return

        raise errors.AFTDeviceError(
            "Failed to find the VM name or virtual hard drive path. Has the " +
            "VirtualBox output format changed?")
Ejemplo n.º 42
0
    def _import_vm(self, ova_appliance):
        """
        Set default VirtualBox directory and import the .ova appliance into
        VirtualBox as a VM
        """
        logger.info("Importing VM appliance")
        self._set_default_directory(
            os.path.join(
                os.getcwd(),
                self._VM_DIRECTORY))

        self._do_import_vm(ova_appliance)
Ejemplo n.º 43
0
    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])
Ejemplo n.º 44
0
 def start_image_usb_emulation(self, args, leases_file):
     """
     Start using the image with USB mass storage emulation
     """
     if self.check_libcomposite_service_running():
         local_execute("systemctl stop libcomposite.service".split())
     self.free_dnsmasq_leases(leases_file)
     image_file = os.path.abspath(args.file_name)
     if not os.path.isfile(image_file):
         print("Image file doesn't exist")
         raise errors.AFTImageNameError("Image file doesn't exist")
     local_execute(("start_libcomposite " + image_file).split())
     logger.info("Started USB mass storage emulation using " + image_file)
Ejemplo n.º 45
0
 def execute(self, device):
     """
     Prepare and executes the test case, storing the results.
     """
     start_time = datetime.datetime.now()
     logger.info("Test case start time: " + str(start_time))
     self._prepare()
     # Test cases are run using the Visitor pattern to allow last-minute
     # preparation of the device for the test.
     self.result = device.test(self)
     self.duration = datetime.datetime.now() - start_time
     logger.info("Test Duration: " + str(self.duration))
     self._build_xunit_section()
Ejemplo n.º 46
0
    def _result_has_zero_fails(self):
        """
        Test if there are FAILED test cases in the QA-test case output
        """
        logger.info(self.output)
#        qa_log_file = open("results-runtest.py.log", "r")
#        qa_log = qa_log_file.read()
#        qa_log_file.close()
        failed_matches = re.findall("FAILED", self.output)
        result = True
        if len(failed_matches) > 0:
            result = False
        return result
Ejemplo n.º 47
0
 def _result_has_zero_fails(self):
     """
     Test if there are FAILED test cases in the QA-test case output
     """
     logger.info(self.output)
     #        qa_log_file = open("results-runtest.py.log", "r")
     #        qa_log = qa_log_file.read()
     #        qa_log_file.close()
     failed_matches = re.findall("FAILED", self.output)
     result = True
     if len(failed_matches) > 0:
         result = False
     return result
Ejemplo n.º 48
0
 def execute(self, device):
     """
     Prepare and executes the test case, storing the results.
     """
     start_time = datetime.datetime.now()
     logger.info("Test case start time: " + str(start_time))
     self._prepare()
     # Test cases are run using the Visitor pattern to allow last-minute
     # preparation of the device for the test.
     self.result = device.test(self)
     self.duration = datetime.datetime.now() - start_time
     logger.info("Test Duration: " + str(self.duration))
     self._build_xunit_section()
Ejemplo n.º 49
0
    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
        ])
Ejemplo n.º 50
0
    def _send_PEM_keystrokes(self, keystrokes, attempts=1, timeout=60):
        """
        Try to send keystrokes within the time limit

        Args:
            keystrokes (str): PEM keystroke file
            attempts (integer): How many attempts will be made
            timeout (integer): Timeout for a single attempt

        Returns:
            None

        Raises:
            aft.errors.AFTDeviceError if PEM connection times out

        """
        def call_pem(exceptions):
            try:
                pem_main(
                [
                    "pem",
                    "--interface", self.pem_interface,
                    "--port", self.pem_port,
                    "--playback", keystrokes
                ])
            except Exception as err:
                exceptions.put(err)

        for i in range(attempts):
            logger.info(
                "Attempt " + str(i + 1) + " of " + str(attempts) + " to send " +
                "keystrokes through PEM")

            exception_queue = Queue()
            process = Process(target=call_pem, args=(exception_queue,))
            # ensure python process is closed in case main process dies but
            # the subprocess is still waiting for timeout
            process.daemon = True

            process.start()
            process.join(timeout)

            if not exception_queue.empty():
                raise exception_queue.get()

            if process.is_alive():
                process.terminate()
            else:
                return

        raise errors.AFTDeviceError("Failed to connect to PEM")
Ejemplo n.º 51
0
    def _do_inject_ssh_key(self):
        """
        Inject ssh key into the mounted virtual hard drive
        """
        logger.info("Injecting ssh key")
        source_file = os.path.join(self._MODULE_DATA_PATH,
                                   self._HARNESS_AUTHORIZED_KEYS_FILE)

        ssh_path = os.path.join(
            os.curdir,
            self._MOUNT_DIRECTORY, "home", "root", ".ssh")

        ssh_file = os.path.join(ssh_path, "authorized_keys")

        logger.info("Injecting ssh key from '" + source_file + "' to '" +
                     ssh_file + "'")

        common.make_directory(ssh_path)
        shutil.copy(source_file, ssh_file)

        sha1sum = misc.local_execute(("sha1sum " +
                ssh_file).split())

        sha1sum = sha1sum.split()[0] # discard the file path

        logger.info("Adding IMA attribute to the ssh-key")

        # The setfattr command requires root privileges to run, and in general
        # we would like to run AFT without root privileges. However, we can add
        # a shell script to the sudoers file, which allows us to invoke it with
        # sudo, without the whole program requiring sudo. Hence, the below commands
        # will succeed even without root privileges.

        # The script also validates that the ssh_file path is at least somewhat
        # sane. This should be taken account if file or directory names are
        # changed

        # Note: Assumes that this file is under aft/devices, and that the shell
        # script is under aft/tools
        setfattr_script = os.path.join(os.path.dirname(__file__), os.path.pardir,
                                     "tools", "setfattr_script.sh")

        misc.local_execute(
            [
                "sudo",
                setfattr_script,
                "0x01" + sha1sum + " ",
                ssh_file
            ])


        logger.info("Fixing ownership and permissions")
        # ensure .ssh directory and authorized key file is owned by root
        os.chown(ssh_path, 0, 0)
        os.chown(ssh_file, 0, 0)

        # and ensure the permissions are correct
        # Note: incompatibility with Python 3 in chmod octal numbers
        os.chmod(ssh_path, 0700)
        os.chmod(ssh_file, 0600)
Ejemplo n.º 52
0
    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)
Ejemplo n.º 53
0
    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])
Ejemplo n.º 54
0
    def _mount_virtual_drive(self):
        """
        Mount the VirtualBox virtual hard drive
        """
        # create mount folder
        common.make_directory(self._MOUNT_DIRECTORY)

        path = os.path.join(
            self._VM_DIRECTORY, self._vm_name,
            self._vhdd);
        logger.info("Mounting '" + path + "' with device '" + self._ROOTFS_DEVICE +
            "' into '" + self._MOUNT_DIRECTORY + "' for ssh key injection")

        misc.local_execute(
            ("guestmount -a " + path +" -m " + self._ROOTFS_DEVICE + " " +
             self._MOUNT_DIRECTORY + " -o allow_other").split())