def _execute(self, cmd, args): template = yield db.get(self.context, 'template') if not template: self._action_log( cmd, 'Cannot deploy %s (%s) because no template was specified' % (self.context.hostname, self.context), system='deploy', logLevel=ERROR) return if (yield db.ro_transact(IDeployed.providedBy)(self.context)): log.msg('Attempt to deploy a deployed compute: %s' % (self.context), system='deploy') return @db.transact def allocate_ip_address(): ippools = db.get_root()['oms_root']['ippools'] ip = ippools.allocate() if ip is not None: self._action_log(cmd, 'Allocated IP: %s for %s' % (ip, self.context), system='deploy') ulog = UserLogger(principal=cmd.protocol.interaction. participations[0].principal, subject=self.context, owner=self.context.__owner__) ulog.log('Allocated IP for %s: %s' % (self.context, ip)) return ip else: raise Exception( 'Could not allocate IP for the new compute: pools exhausted or undefined' ) @db.transact def cleanup_root_password(): if getattr(self.context, 'root_password', None) is not None: self.context.root_password = None @db.transact def adjust_cpulimit(): """Set cpulimit to a configured percentage * cores""" cores = getattr(self.context, 'num_cores', 1) cpu_limit_factor = get_config().getfloat('vms', 'cpu_limit', 80) cpu_limit = cores * cpu_limit_factor / 100.0 log.msg("Updating cpulimit to %s" % cpu_limit, system='deploy') self.context.cpu_limit = cpu_limit target = (args if IVirtualizationContainer.providedBy(args) else (yield db.get(self.context, '__parent__'))) try: yield db.transact(alsoProvides)(self.context, IDeploying) vm_parameters = yield self.get_parameters() ipaddr = netaddr.IPAddress(vm_parameters['ip_address']) if vm_parameters['ip_address'] in (None, u'0.0.0.0/32', u'0.0.0.0', '0.0.0.0/32', '0.0.0.0'): ipaddr = yield allocate_ip_address() vm_parameters.update({'ip_address': str(ipaddr)}) utils = getAllUtilitiesRegisteredFor(IPreDeployHook) for util in utils: yield defer.maybeDeferred(util.execute, self.context, cmd, vm_parameters) log.msg('Deploying %s to %s: issuing agent command' % (self.context, target), system='deploy') res = yield IVirtualizationContainerSubmitter(target).submit( IDeployVM, vm_parameters) yield cleanup_root_password() yield adjust_cpulimit() name = yield db.get(self.context, '__name__') hostname = yield db.get(self.context, 'hostname') owner = yield db.get(self.context, '__owner__') owner_obj = getUtility(IAuthentication).getPrincipal(owner) log.msg('Checking post-deploy...', system='deploy') @db.transact def set_notify_admin(): if self.context.notify_admin: self.context.license_activated = False admin_logger.warning( '%s (hostname=%s; owner=%s; targethost=%s(%s); ipaddr=%s) ' 'requires activation!', self.context, self.context.hostname, self.context.__owner__, target.__parent__, target.__parent__.hostname, vm_parameters['ip_address']) yield set_notify_admin() if not (yield self._check_vm_post(cmd, name, hostname, target)): self._action_log(cmd, 'Deployment failed. Request result: %s' % res, system='deploy') return @db.transact def add_deployed_model_remove_from_hangar(c, target): path = canonical_path(target) target = traverse1(path) cpath = canonical_path(c) c = traverse1(cpath) if c is None: raise Exception('Compute not found: "%s"' % cpath) new_compute = Compute(unicode(hostname), u'inactive') new_compute.__name__ = name new_compute.__owner__ = owner_obj new_compute.template = unicode(template) new_compute._ipv4_address = unicode(ipaddr) new_compute.mac_address = getattr(c, 'mac_address', None) new_compute.memory = getattr(c, 'memory', 0) new_compute.diskspace = getattr(c, 'diskspace', {u'total': 0}) new_compute.num_cores = getattr(c, 'num_cores', 0) new_compute.license_activated = getattr( c, 'license_activated', True) alsoProvides(new_compute, IVirtualCompute) alsoProvides(new_compute, IDeployed) noLongerProvides(new_compute, IManageable) target.add(new_compute) container = c.__parent__ del container[name] timestamp = int(time.time() * 1000) IStream(new_compute).add((timestamp, { 'event': 'change', 'name': 'features', 'value': new_compute.features, 'old_value': self.context.features })) IStream(new_compute).add((timestamp, { 'event': 'change', 'name': 'ipv4_address', 'value': new_compute._ipv4_address, 'old_value': self.context._ipv4_address })) yield add_deployed_model_remove_from_hangar(self.context, target) self._action_log( cmd, 'Deployment of "%s"(%s) is finished' % (vm_parameters['hostname'], self.context.__name__), system='deploy') auto_allocate = get_config().getboolean('vms', 'auto_allocate', True) if not auto_allocate and not get_config().getboolean( 'stats', 'only_report_on_sync', True): yield defer.maybeDeferred( getUtility(IUserStatisticsProvider).update, owner) except Exception as e: log.err(system='deploy') @db.transact def cleanup_deploying(): noLongerProvides(self.context, IDeploying) yield cleanup_deploying() raise e
def _execute(self, cmd, args): template = yield db.get(self.context, 'template') if not template: self._action_log(cmd, 'Cannot deploy %s (%s) because no template was specified' % (self.context.hostname, self.context), system='deploy', logLevel=ERROR) return if (yield db.ro_transact(IDeployed.providedBy)(self.context)): log.msg('Attempt to deploy a deployed compute: %s' % (self.context), system='deploy') return @db.transact def allocate_ip_address(): ippools = db.get_root()['oms_root']['ippools'] ip = ippools.allocate() if ip is not None: self._action_log(cmd, 'Allocated IP: %s for %s' % (ip, self.context), system='deploy') ulog = UserLogger(principal=cmd.protocol.interaction.participations[0].principal, subject=self.context, owner=self.context.__owner__) ulog.log('Allocated IP for %s: %s' % (self.context, ip)) return ip else: raise Exception('Could not allocate IP for the new compute: pools exhausted or undefined') @db.transact def cleanup_root_password(): if getattr(self.context, 'root_password', None) is not None: self.context.root_password = None target = (args if IVirtualizationContainer.providedBy(args) else (yield db.get(self.context, '__parent__'))) try: yield db.transact(alsoProvides)(self.context, IDeploying) vm_parameters = yield self.get_parameters() ipaddr = netaddr.IPAddress(vm_parameters['ip_address']) if vm_parameters['ip_address'] in (None, u'0.0.0.0/32', u'0.0.0.0', '0.0.0.0/32', '0.0.0.0'): ipaddr = yield allocate_ip_address() vm_parameters.update({'ip_address': str(ipaddr)}) utils = getAllUtilitiesRegisteredFor(IPreDeployHook) for util in utils: yield defer.maybeDeferred(util.execute, self.context, cmd, vm_parameters) log.msg('Deploying %s to %s: issuing agent command' % (self.context, target), system='deploy') res = yield IVirtualizationContainerSubmitter(target).submit(IDeployVM, vm_parameters) yield cleanup_root_password() name = yield db.get(self.context, '__name__') hostname = yield db.get(self.context, 'hostname') owner = yield db.get(self.context, '__owner__') owner_obj = getUtility(IAuthentication).getPrincipal(owner) log.msg('Checking post-deploy...', system='deploy') if not (yield self._check_vm_post(cmd, name, hostname, target)): self._action_log(cmd, 'Deployment failed. Deployment request result: %s' % res, system='deploy') return @db.transact def add_deployed_model_remove_from_hangar(c, target): path = canonical_path(target) target = traverse1(path) cpath = canonical_path(c) c = traverse1(cpath) if c is None: raise Exception('Compute not found: "%s"' % cpath) new_compute = Compute(unicode(hostname), u'inactive') new_compute.__name__ = name new_compute.__owner__ = owner_obj new_compute.template = unicode(template) new_compute._ipv4_address = unicode(ipaddr) new_compute.mac_address = getattr(c, 'mac_address', None) new_compute.memory = getattr(c, 'memory', 0) new_compute.diskspace = getattr(c, 'diskspace', {u'total': 0}) new_compute.num_cores = getattr(c, 'num_cores', 0) alsoProvides(new_compute, IVirtualCompute) alsoProvides(new_compute, IDeployed) noLongerProvides(new_compute, IManageable) target.add(new_compute) container = c.__parent__ del container[name] timestamp = int(time.time() * 1000) IStream(new_compute).add((timestamp, {'event': 'change', 'name': 'features', 'value': new_compute.features, 'old_value': self.context.features})) IStream(new_compute).add((timestamp, {'event': 'change', 'name': 'ipv4_address', 'value': new_compute._ipv4_address, 'old_value': self.context._ipv4_address})) yield add_deployed_model_remove_from_hangar(self.context, target) self._action_log(cmd, 'Deployment of "%s"(%s) is finished' % (vm_parameters['hostname'], self.context.__name__), system='deploy') auto_allocate = get_config().getboolean('vms', 'auto_allocate', True) if not auto_allocate and not get_config().getboolean('stats', 'only_report_on_sync', True): yield defer.maybeDeferred(getUtility(IUserStatisticsProvider).update, owner) except Exception as e: log.err(system='deploy') @db.transact def cleanup_deploying(): noLongerProvides(self.context, IDeploying) yield cleanup_deploying() raise e
def _execute(self, cmd, args): if (yield db.ro_transact(IDeployed.providedBy)(self.context)): log.msg('Attempt to allocate a deployed compute: %s' % (self.context), system='deploy') return yield db.transact(alsoProvides)(self.context, IAllocating) @db.ro_transact def get_matching_machines(container): all_machines = db.get_root()['oms_root']['machines'] param = unicode(get_config().getstring('allocate', 'diskspace_filter_param', default=u'/storage')) def condition_generator(m): yield ICompute.providedBy(m) yield find_compute_v12n_container(m, container) yield not getattr(m, 'exclude_from_allocation', None) yield not getattr(m, 'failure', None) if not get_config().getboolean('overcommit', 'memory', False): yield self.context.memory_usage < m.memory else: log.msg('Memory filtering is disabled.', system='action-allocate') if not get_config().getboolean('overcommit', 'disk', False): yield sum( map( lambda (pk, pv): pv, filter(lambda (pk, pv): pk != 'total', self.context.diskspace.iteritems()))) < ( m.diskspace.get(param, 0) - m.diskspace_usage.get(param, 0)) else: log.msg('Diskspace filtering is disabled.', system='action-allocate') if not get_config().getboolean('overcommit', 'cores', False): yield self.context.num_cores <= m.num_cores else: log.msg('\'Total # of cores\' filtering is disabled.', system='action-allocate') templates = m['vms-%s' % container]['templates'] yield self.context.template in map( lambda t: t.name, filter(lambda t: ITemplate.providedBy(t), templates.listcontent() if templates else [])) def unwind_until_false(generator): fail_description = [ 'Not a compute', 'No virt container %s' % container, 'In a failed state - not responding to ping', 'Excluded from allocation', 'Has less than %s MB memory' % self.context.memory_usage, 'Not enough diskspace', 'Not enough CPU cores', 'Template is unavailable' ] try: for idx, r in enumerate(generator): if not r: return 'Fail at %d: %s' % (idx, fail_description[idx]) return 'Match' except Exception as e: log.err(system='action-allocate') return 'Fail (exception)' % (fail_description, e) results = map( lambda m: (str(m), unwind_until_false(condition_generator(m))), all_machines) log.msg('Searching in: %s' % (results), logLevel=DEBUG, system='action-allocate') return filter(lambda m: all(condition_generator(m)), all_machines) try: log.msg('Allocating %s: searching for targets...' % self.context, system='action-allocate') vmsbackend = yield db.ro_transact( lambda: self.context.__parent__.backend)() machines = yield get_matching_machines(vmsbackend) if len(machines) <= 0: self._action_log(cmd, 'Found no fitting machines. Action aborted.', system='action-allocate', logLevel=WARNING) return @db.ro_transact def rank(machines): return sorted(machines, key=lambda m: m.__name__) best = (yield rank(machines))[0] log.msg( 'Found %s as the best candidate. Attempting to allocate...' % (best), system='action-allocate') bestvmscontainer = yield db.ro_transact( find_compute_v12n_container)(best, vmsbackend) @db.transact def set_additional_keys(): self._additional_keys = [ canonical_path(best), canonical_path(bestvmscontainer) ] yield set_additional_keys() yield self.reacquire_until_clear() yield DeployAction(self.context)._execute(DetachedProtocol(), bestvmscontainer) finally: yield db.transact(noLongerProvides)(self.context, IAllocating)