Loading cloudcontrol/server/clients/cli.py +23 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ from sjrpc.core import RpcError from cloudcontrol.common.datastructures.orderedset import OrderedSet from cloudcontrol.common.allocation.vmspec import expand_vmspec from cloudcontrol.server.conf import CCConf from cloudcontrol.server.exceptions import (ReservedTagError, BadRoleError, NotConnectedAccountError, CloneError) Loading @@ -26,7 +28,7 @@ from cloudcontrol.server.repository import RepositoryOperationError from cloudcontrol.server.handlers import listed, Reporter from cloudcontrol.server.clients import Client, RegisteredCCHandler from cloudcontrol.server.jobs import (ColdMigrationJob, HotMigrationJob, CloneJob, KillClientJob) CloneJob, KillClientJob, AllocationJob) from cloudcontrol.common.tql.db.tag import StaticTag MIGRATION_TYPES = {'cold': ColdMigrationJob, Loading Loading @@ -1012,7 +1014,7 @@ class CliHandler(RegisteredCCHandler): return errs.get_dict() # # Election / Migration / Cloning: # Election / Migration / Cloning / Allocation # @listed Loading Loading @@ -1102,6 +1104,25 @@ class CliHandler(RegisteredCCHandler): 'hv_dest': dest['id']}) return job.id @listed def allocate(self, vmspec, tql_target): """ Allocate new VMs. :param vmspec: a vmspec structure :param tql_target: a TQL used as target restriction """ self.client.check('allocate') # Check and expand vmspec input: expanded_vmspec = expand_vmspec(vmspec) job = self.client.spawn_job(AllocationJob, settings={'server': self.server, 'client': self.client, 'expanded_vmspec': expanded_vmspec, 'tql_target': tql_target}) return job.id # # Remote console: # Loading cloudcontrol/server/jobs/__init__.py +2 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,8 @@ from cloudcontrol.server.jobs.hotmigration import HotMigrationJob from cloudcontrol.server.jobs.clone import CloneJob from cloudcontrol.server.jobs.killoldcli import KillOldCliJob from cloudcontrol.server.jobs.killclient import KillClientJob from cloudcontrol.server.jobs.allocation import AllocationJob __all__ = ('ColdMigrationJob', 'HotMigrationJob', 'CloneJob', 'KillOldCliJob', 'KillClientJob') No newline at end of file 'KillClientJob', 'AllocationJob') No newline at end of file cloudcontrol/server/jobs/allocation.py 0 → 100644 +86 −0 Original line number Diff line number Diff line # 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 <http://www.gnu.org/licenses/>. 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') Loading
cloudcontrol/server/clients/cli.py +23 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ from sjrpc.core import RpcError from cloudcontrol.common.datastructures.orderedset import OrderedSet from cloudcontrol.common.allocation.vmspec import expand_vmspec from cloudcontrol.server.conf import CCConf from cloudcontrol.server.exceptions import (ReservedTagError, BadRoleError, NotConnectedAccountError, CloneError) Loading @@ -26,7 +28,7 @@ from cloudcontrol.server.repository import RepositoryOperationError from cloudcontrol.server.handlers import listed, Reporter from cloudcontrol.server.clients import Client, RegisteredCCHandler from cloudcontrol.server.jobs import (ColdMigrationJob, HotMigrationJob, CloneJob, KillClientJob) CloneJob, KillClientJob, AllocationJob) from cloudcontrol.common.tql.db.tag import StaticTag MIGRATION_TYPES = {'cold': ColdMigrationJob, Loading Loading @@ -1012,7 +1014,7 @@ class CliHandler(RegisteredCCHandler): return errs.get_dict() # # Election / Migration / Cloning: # Election / Migration / Cloning / Allocation # @listed Loading Loading @@ -1102,6 +1104,25 @@ class CliHandler(RegisteredCCHandler): 'hv_dest': dest['id']}) return job.id @listed def allocate(self, vmspec, tql_target): """ Allocate new VMs. :param vmspec: a vmspec structure :param tql_target: a TQL used as target restriction """ self.client.check('allocate') # Check and expand vmspec input: expanded_vmspec = expand_vmspec(vmspec) job = self.client.spawn_job(AllocationJob, settings={'server': self.server, 'client': self.client, 'expanded_vmspec': expanded_vmspec, 'tql_target': tql_target}) return job.id # # Remote console: # Loading
cloudcontrol/server/jobs/__init__.py +2 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,8 @@ from cloudcontrol.server.jobs.hotmigration import HotMigrationJob from cloudcontrol.server.jobs.clone import CloneJob from cloudcontrol.server.jobs.killoldcli import KillOldCliJob from cloudcontrol.server.jobs.killclient import KillClientJob from cloudcontrol.server.jobs.allocation import AllocationJob __all__ = ('ColdMigrationJob', 'HotMigrationJob', 'CloneJob', 'KillOldCliJob', 'KillClientJob') No newline at end of file 'KillClientJob', 'AllocationJob') No newline at end of file
cloudcontrol/server/jobs/allocation.py 0 → 100644 +86 −0 Original line number Diff line number Diff line # 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 <http://www.gnu.org/licenses/>. 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')