Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
    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)