1faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao# Copyright (c) 2013 The Chromium Authors. All rights reserved.
2faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao# Use of this source code is governed by a BSD-style license that can be
3faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao# found in the LICENSE file.
4faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
5faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gaoimport logging
6e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gaoimport random
7faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
8faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gaofrom time import sleep
9faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
102e4e57453f2713d12f79734e2ab3f03b4371a99dAlex Millerimport common
11fe3237a922ced95b3178859a8262098e6e55e164Jason Abelefrom autotest_lib.client.common_lib import utils
1222093e32603a2c850e8a15121f4718f15e435415Roshan Piusfrom autotest_lib.server.cros.ap_configurators import \
13faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    ap_configurator_factory
1422093e32603a2c850e8a15121f4718f15e435415Roshan Piusfrom autotest_lib.client.common_lib.cros.network import ap_constants
1522093e32603a2c850e8a15121f4718f15e435415Roshan Piusfrom autotest_lib.server.cros.ap_configurators import ap_cartridge
16faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
17faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
18faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao# Max number of retry attempts to lock an ap.
19faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan GaoMAX_RETRIES = 3
20faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
21faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
22faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gaoclass ApLocker(object):
23faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    """Object to keep track of AP lock state.
24faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
25faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @attribute configurator: an APConfigurator object.
26faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @attribute to_be_locked: a boolean, True iff ap has not been locked.
27faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @attribute retries: an integer, max number of retry attempts to lock ap.
28faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    """
29faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
30faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
31faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    def __init__(self, configurator, retries):
32faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """Initialize.
33faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
34faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        @param configurator: an APConfigurator object.
35faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        @param retries: an integer, max number of retry attempts to lock ap.
36faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """
37faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        self.configurator = configurator
38faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        self.to_be_locked = True
39faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        self.retries = retries
40faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
41faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
42faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    def __repr__(self):
43faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """@return class name, ap host name, lock status and retries."""
44faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        return 'class: %s, host name: %s, to_be_locked = %s, retries = %d' % (
45faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                self.__class__.__name__,
46faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                self.configurator.host_name,
47faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                self.to_be_locked,
48faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                self.retries)
49faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
50faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
5122093e32603a2c850e8a15121f4718f15e435415Roshan Piusdef construct_ap_lockers(ap_spec, retries, hostname_matching_only=False,
5222093e32603a2c850e8a15121f4718f15e435415Roshan Pius                         ap_test_type=ap_constants.AP_TEST_TYPE_CHAOS):
53faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    """Convert APConfigurator objects to ApLocker objects for locking.
54faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
55506a99d582456eff2f6d5e534cbf00a62990e97dKris Rambish    @param ap_spec: an APSpec object
56faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @param retries: an integer, max number of retry attempts to lock ap.
5748407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish    @param hostname_matching_only: a boolean, if True matching against
5848407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish                                   all other APSpec parameters is not
5948407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish                                   performed.
6022093e32603a2c850e8a15121f4718f15e435415Roshan Pius    @param ap_test_type: Used to determine which type of test we're
6122093e32603a2c850e8a15121f4718f15e435415Roshan Pius                         currently running (Chaos vs Clique).
6248407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish
63faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @return a list of ApLocker objects.
64faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    """
65faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    ap_lockers_list = []
66d2ae97483945e7f78e57e41cafcd800553e08598Tien Chang    factory = ap_configurator_factory.APConfiguratorFactory(ap_test_type,
67d2ae97483945e7f78e57e41cafcd800553e08598Tien Chang                                                            ap_spec)
6848407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish    if hostname_matching_only:
6948407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish        for ap in factory.get_aps_by_hostnames(ap_spec.hostnames):
7048407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish            ap_lockers_list.append(ApLocker(ap, retries))
7148407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish    else:
7248407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish        for ap in factory.get_ap_configurators_by_spec(ap_spec):
7348407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish            ap_lockers_list.append(ApLocker(ap, retries))
74faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
75c00e83b0c1d8eac549a633d44dccebf0fb8eb875Christopher Wiley    if not len(ap_lockers_list):
7613fad55d8088ec511d93f31b1c3813a907aef141Tien Chang        logging.error('Found no matching APs to test against for %s', ap_spec)
77c00e83b0c1d8eac549a633d44dccebf0fb8eb875Christopher Wiley
78faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    logging.debug('Found %d APs', len(ap_lockers_list))
79faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    return ap_lockers_list
80faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
81faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
82faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gaoclass ApBatchLocker(object):
83faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    """Object to lock/unlock an APConfigurator.
84faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
85faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @attribute SECONDS_TO_SLEEP: an integer, number of seconds to sleep between
86faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                                 retries.
87506a99d582456eff2f6d5e534cbf00a62990e97dKris Rambish    @attribute ap_spec: an APSpec object
88faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @attribute retries: an integer, max number of retry attempts to lock ap.
89faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                        Defaults to MAX_RETRIES.
90faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @attribute aps_to_lock: a list of ApLocker objects.
91faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    @attribute manager: a HostLockManager object, used to lock/unlock APs.
92faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    """
93faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
94faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
95e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao    MIN_SECONDS_TO_SLEEP = 30
96e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao    MAX_SECONDS_TO_SLEEP = 120
97faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
98faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
9948407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish    def __init__(self, lock_manager, ap_spec, retries=MAX_RETRIES,
10022093e32603a2c850e8a15121f4718f15e435415Roshan Pius                 hostname_matching_only=False,
10122093e32603a2c850e8a15121f4718f15e435415Roshan Pius                 ap_test_type=ap_constants.AP_TEST_TYPE_CHAOS):
102faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """Initialize.
103faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
104506a99d582456eff2f6d5e534cbf00a62990e97dKris Rambish        @param ap_spec: an APSpec object
105faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        @param retries: an integer, max number of retry attempts to lock ap.
106faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                        Defaults to MAX_RETRIES.
10748407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish        @param hostname_matching_only : a boolean, if True matching against
10848407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish                                        all other APSpec parameters is not
10948407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish                                        performed.
11022093e32603a2c850e8a15121f4718f15e435415Roshan Pius        @param ap_test_type: Used to determine which type of test we're
11122093e32603a2c850e8a15121f4718f15e435415Roshan Pius                             currently running (Chaos vs Clique).
112faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """
11348407e81a9fe4dbb13609b2f871761d02123e237Kris Rambish        self.aps_to_lock = construct_ap_lockers(ap_spec, retries,
11422093e32603a2c850e8a15121f4718f15e435415Roshan Pius                           hostname_matching_only=hostname_matching_only,
11522093e32603a2c850e8a15121f4718f15e435415Roshan Pius                           ap_test_type=ap_test_type)
116ca4e36ca5d3a37f4c8438e9545ff93fff284653cChristopher Wiley        self.manager = lock_manager
117ca4e36ca5d3a37f4c8438e9545ff93fff284653cChristopher Wiley        self._locked_aps = []
118faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
119faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
120faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    def has_more_aps(self):
121faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """@return True iff there is at least one AP to be locked."""
122faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        return len(self.aps_to_lock) > 0
123faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
124faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
125faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    def lock_ap_in_afe(self, ap_locker):
126faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """Locks an AP host in AFE.
127faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
128faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        @param ap_locker: an ApLocker object, AP to be locked.
129faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        @return a boolean, True iff ap_locker is locked.
130faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """
131fe3237a922ced95b3178859a8262098e6e55e164Jason Abele        if not utils.host_is_in_lab_zone(ap_locker.configurator.host_name):
132fe3237a922ced95b3178859a8262098e6e55e164Jason Abele            ap_locker.to_be_locked = False
133fe3237a922ced95b3178859a8262098e6e55e164Jason Abele            return True
134fe3237a922ced95b3178859a8262098e6e55e164Jason Abele
135751b85445709dc1015a6b31b8b51b379abbfdc78Tan Gao        if self.manager.lock([ap_locker.configurator.host_name]):
136ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish            self._locked_aps.append(ap_locker)
137e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            logging.info('locked %s', ap_locker.configurator.host_name)
138faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao            ap_locker.to_be_locked = False
139faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao            return True
140e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao        else:
141faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao            ap_locker.retries -= 1
142faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao            logging.info('%d retries left for %s',
143faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                         ap_locker.retries,
144faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                         ap_locker.configurator.host_name)
145faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao            if ap_locker.retries == 0:
146faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                logging.info('No more retries left. Remove %s from list',
147faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                             ap_locker.configurator.host_name)
148e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                ap_locker.to_be_locked = False
149e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
150faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        return False
151faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
152faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
153faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao    def get_ap_batch(self, batch_size=ap_cartridge.THREAD_MAX):
154faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """Allocates a batch of locked APs.
155faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao
156faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        @param batch_size: an integer, max. number of aps to lock in one batch.
157faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao                           Defaults to THREAD_MAX in ap_cartridge.py
158faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        @return a list of APConfigurator objects, locked on AFE.
159faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        """
160faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        # We need this while loop to continuously loop over the for loop.
161faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        # To exit the while loop, we either:
162faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        #  - locked batch_size number of aps and return them
163faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao        #  - exhausted all retries on all aps in aps_to_lock
164e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao        while len(self.aps_to_lock):
165e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            ap_batch = []
166e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
167faf1fbb13009fcbc3342b6d3226f28aa3dc177fcTan Gao            for ap_locker in self.aps_to_lock:
168e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                logging.info('checking %s', ap_locker.configurator.host_name)
169e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                if self.lock_ap_in_afe(ap_locker):
170e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                    ap_batch.append(ap_locker.configurator)
171e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                    if len(ap_batch) == batch_size:
172e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                        break
173e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
174e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            # Remove locked APs from list of APs to process.
175e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            aps_to_rm = [ap for ap in self.aps_to_lock if not ap.to_be_locked]
176e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            self.aps_to_lock = list(set(self.aps_to_lock) - set(aps_to_rm))
177e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            for ap in aps_to_rm:
178e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                logging.info('Removed %s from self.aps_to_lock',
179e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                             ap.configurator.host_name)
180e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            logging.info('Remaining aps to lock = %s',
181e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                         [ap.configurator.host_name for ap in self.aps_to_lock])
182e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
183e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            # Return available APs and retry remaining ones later.
184e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            if ap_batch:
185e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                return ap_batch
186e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
187e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            # Sleep before next retry.
188e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao            if self.aps_to_lock:
189e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                seconds_to_sleep = random.randint(self.MIN_SECONDS_TO_SLEEP,
190e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                                                  self.MAX_SECONDS_TO_SLEEP)
191e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                logging.info('Sleep %d sec before retry', seconds_to_sleep)
192e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao                sleep(seconds_to_sleep)
193e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
194e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao        return []
195e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
196e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao
197ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish    def unlock_one_ap(self, host_name):
198751b85445709dc1015a6b31b8b51b379abbfdc78Tan Gao        """Unlock one AP after we're done.
199751b85445709dc1015a6b31b8b51b379abbfdc78Tan Gao
200ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        @param host_name: a string, host name.
201751b85445709dc1015a6b31b8b51b379abbfdc78Tan Gao        """
202ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        for ap_locker in self._locked_aps:
203ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish            if host_name == ap_locker.configurator.host_name:
204ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish                self.manager.unlock(hosts=[host_name])
2055320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish                self._locked_aps.remove(ap_locker)
206ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish                return
207ca4e36ca5d3a37f4c8438e9545ff93fff284653cChristopher Wiley
208ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        logging.error('Tried to unlock a host we have not locked (%s)?',
209ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish                      host_name)
210751b85445709dc1015a6b31b8b51b379abbfdc78Tan Gao
211751b85445709dc1015a6b31b8b51b379abbfdc78Tan Gao
212e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao    def unlock_aps(self):
213e6f9c09d74b8823c16de839a18a571149c7b8740Tan Gao        """Unlock APs after we're done."""
2145320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish        # Make a copy of all of the hostnames to process
2155320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish        host_names = list()
216ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        for ap_locker in self._locked_aps:
2175320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish            host_names.append(ap_locker.configurator.host_name)
2185320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish        for host_name in host_names:
2195320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish            self.unlock_one_ap(host_name)
220ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish
221ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish
2221afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish    def unlock_and_reclaim_ap(self, host_name):
2231afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish        """Unlock an AP but return it to the remaining batch of APs.
2241afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish
2251afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish        @param host_name: a string, host name.
2261afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish        """
2271afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish        for ap_locker in self._locked_aps:
2281afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish            if host_name == ap_locker.configurator.host_name:
2295320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish                self.aps_to_lock.append(ap_locker)
2305320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish                self.unlock_one_ap(host_name)
2315320048ccfec8291a1b84838eeb925f2e0bb1965Kris Rambish                return
2321afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish
2331afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish
234ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish    def unlock_and_reclaim_aps(self):
2351afc69706f835eee0cd324e2aaf3f59101f89a69Kris Rambish        """Unlock APs but return them to the batch of remining APs.
236ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish
237ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        unlock_aps() will remove the remaining APs from the list of all APs
238ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        to process.  This method will add the remaining APs back to the pool
239ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        of unprocessed APs.
240ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish
241ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        """
242ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        # Add the APs back into the pool
243ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        self.aps_to_lock.extend(self._locked_aps)
244ba0006bba9e24725aefb3c123ed5e88946ebafa4Kris Rambish        self.unlock_aps()
245