# This file is part of CloudControl. # # CloudControl is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # CloudControl is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with CloudControl. If not, see . import threading from cloudcontrol.common.jobs import Job from cloudcontrol.server.allocator import Allocator, AllocationError class DeployError(Exception): """ Exception raised when an error occurs while deploying a virtual machine on an hypervisor. """ class AllocationJob(Job): """ Allocate a set of VM on hypervisors. """ # Global allocation lock. Must be locked before to do allocation for a # single virtual machine: allocation_lock = threading.Lock() def job(self, server, client, expanded_vmspec, tql_target=None): allocator = Allocator(self.logger.getChild('allocator'), server, client) results_by_vm = {} total = len(expanded_vmspec) errors = 0 for i, vmspec in enumerate(expanded_vmspec): self.title = 'Virtual machines allocation (%d/%d, %d errors)' % (i + 1, total, errors) with AllocationJob.allocation_lock: self.checkpoint() try: target_hv_name = allocator.allocate(vmspec, tql_target)[0] except AllocationError, err: self.logger.warn('VM %s: allocation error: %s. Skipping...' % (vmspec['title'], err)) results_by_vm[vmspec['title']] = 'allocation error, %s' % err errors += 1 except Exception, err: self.logger.exception('VM %s: unknow error while allocation: %s. Skipping...' % (vmspec['title'], err)) results_by_vm[vmspec['title']] = 'unknown error (see logs)' errors += 1 else: # Keep the VM target in a tag for future migrations if 'tags' not in vmspec: vmspec['tags'] = {} vmspec['tags'].setdefault('target', vmspec['target']) try: vm_uuid = self._deploy(vmspec, server.get_client(target_hv_name)) except Exception as err: results_by_vm[vmspec['title']] = 'Error: %s' % err errors += 1 else: self.logger.info('VM %s: spawned on %s' % (vmspec['title'], target_hv_name)) results_by_vm[vmspec['title']] = 'spawned %s on %s' % (vm_uuid, target_hv_name) # Write a summary of the Allocation job in the results attachment: results = self.attachment('results') for vm_name, result in results_by_vm.iteritems(): results.write('%s: %s\n' % (vm_name, result)) def _deploy(self, vmspec, target_hv): # Delete keys which are not recognized by subsequent components: for key in ('target', 'flags', 'riskgroup'): try: del vmspec[key] except KeyError: pass return target_hv.define(vmspec, format='vmspec')