def find_device(self): self.logger.info('Finding device.') device_name = None count = self.machine.increment_counter(self.state_name) request = data.request_config(self.machine.request_id) image_is_reusable = data.image_is_reusable(request['image']) free_devices = data.get_free_devices( environment=request['environment'], device_name=request['requested_device']) if free_devices: if image_is_reusable: devices_with_image = [x for x in free_devices if x['image'] == request['image'] and data.from_json(x['boot_config']) == data.from_json(request['boot_config'])] if devices_with_image: free_devices = devices_with_image # pick a device at random from the returned list device_name = random.choice(free_devices)['name'] self.logger.info('Assigning device %s.' % device_name) if data.reserve_device(self.machine.request_id, device_name): self.logger.info('Request succeeded.') self.machine.goto_state(contacting_lifeguard) else: self.logger.warn('Request failed!') if request['requested_device'] == 'any': if count >= self.MAX_ANY_REQUESTS: self.logger.warn('Hit maximum number of attempts to find ' 'a free device; giving up.') self.machine.goto_state(device_not_found) else: if count >= self.MAX_SPECIFIC_REQUESTS: self.logger.warn('Requested device %s is busy.' % device_name) self.machine.goto_state(device_busy)
def contact_lifeguard(self, request_config): # If the requested image is reusable and we got a device with that # image and the requested bootconfig, just power cycle it. # Otherwise, image it. Note that there will be a failure if the # image is not installed and the device is not imageable. event = '' device_request_data = {} assigned_device_name = request_config['assigned_device'] if data.image_is_reusable(request_config['image']): device_config = data.device_config(request_config['assigned_device']) if (device_config['image'] == request_config['image'] and data.from_json(device_config['boot_config']) == data.from_json(request_config['boot_config'])): event = 'please_power_cycle' if not event: # Use the device's hardware type and requested image to find the # pxe config, if any. event = 'please_image' device_request_data['boot_config'] = request_config['boot_config'] device_request_data['image'] = request_config['image'] device_url = 'http://%s/api/device/%s/event/%s/' % ( data.get_server_for_device(assigned_device_name), assigned_device_name, event) # FIXME: make this asynchronous so slow/missing servers don't halt # the state machine. try: urllib.urlopen(device_url, json.dumps(device_request_data)) except IOError: self.logger.warn('Could not contact lifeguard server at %s' % device_url) return False return True