| # Copyright (c) 2019 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server import test |
| from autotest_lib.server import frontend |
| |
| class hardware_StorageQualCheckSetup(test.test): |
| """ |
| Verifies the moblab and DUT setup for storage qual |
| A correct setup consists of |
| At least one pool (the default "no pool" counts as a pool) |
| Each of the labels [retention, trim, suspend] is applied to exactly |
| one DUT in the pool. |
| No duplication of the labels, all labels are applied exactly once |
| per pool |
| |
| The test will verify this set up, for the pool that is selected on the |
| RunSuite page (by getting the pool of the DUT running the test). If this |
| test passes, we have confidence that this individual pool is a valid setup |
| for storage qual. |
| """ |
| |
| version = 1 |
| |
| REQUIRED_LABELS = ['retention', 'trim', 'suspend'] |
| |
| def _group_hosts_into_pools(self, hosts): |
| pools = {} |
| for host in hosts: |
| labels = [label.name for label in host.get_labels()] |
| |
| pool_name = 'none' |
| for label in labels: |
| if 'pool:' in label: |
| pool_name = label.replace('pool:', '') |
| |
| if pool_name not in pools: |
| pools[pool_name] = [] |
| |
| pools[pool_name].append({ |
| 'host': host.hostname, |
| 'labels': labels |
| }) |
| |
| return pools |
| |
| def _get_running_host_pool(self): |
| host = list(self.job.hosts)[0] |
| pools = host.host_info_store.get().pools |
| return list(pools)[0] if len(pools) > 0 else 'none' |
| |
| def run_once(self): |
| """ Tests the moblab's connected DUTs to see if the current |
| configuration is valid for storage qual |
| """ |
| |
| # get the pool of the host this test is running on |
| pool_name = self._get_running_host_pool() |
| logging.info('Test is running on pool %s', pool_name) |
| |
| afe = frontend.AFE(server='localhost', user='moblab') |
| |
| # get autotest statuses that indicate a live host |
| live_statuses = afe.host_statuses(live=True) |
| |
| # get the hosts connected to autotest, find the live ones |
| hosts = [] |
| for host in afe.get_hosts(): |
| if host.status in live_statuses: |
| logging.info('Host %s is live, status %s', |
| host.hostname, host.status) |
| hosts.append(host) |
| else: |
| logging.info('Host %s is not live, status %s', |
| host.hostname, host.status) |
| |
| pools = self._group_hosts_into_pools(hosts) |
| |
| # verify that the pool is set up to run storage qual, with correct |
| # number of DUTs and correct labels |
| required_set = set(self.REQUIRED_LABELS) |
| provided_set = set() |
| for host in pools[pool_name]: |
| host_provided_labels = set(host['labels']) & required_set |
| # check that each DUT has at most 1 storage qual label |
| if len(host_provided_labels) > 1: |
| raise error.TestFail( |
| ('Host %s is assigned more than ' |
| 'one storage qual label %s') % |
| (host['host'], str(host_provided_labels))) |
| if len(host_provided_labels) == 0: |
| continue |
| |
| # check that each label is only on one DUT in the pool |
| provided_label = host_provided_labels.pop() |
| if provided_label in provided_set: |
| raise error.TestFail( |
| ('Host %s is assigned label %s, which is already ' |
| 'assigned to another DUT in pool %s') % |
| (host['host'], provided_label, pool_name) |
| ) |
| |
| provided_set.add(provided_label) |
| logging.info(' - %s %s', host['host'], provided_label) |
| |
| # check that all storage qual labels are accounted for in the pool |
| missing_labels = required_set - provided_set |
| if len(missing_labels) > 0: |
| raise error.TestFail( |
| 'Pool %s is missing required labels %s' % |
| (pool_name, str(missing_labels)) |
| ) |
| |
| return |