Esempio n. 1
0
    def _find_most_matching_networks(self, requested_networks, candidates):
        if not candidates:
            return []

        # Find number of matching networks on each node
        candidates_network_matches = {}
        for node in candidates:
            candidates_network_matches[node] = 0

            # Make a list of networks for the node
            present_networks = []
            for inst in list(db.get_instances(only_node=node)):
                for iface in db.get_instance_interfaces(inst['uuid']):
                    if not iface['network_uuid'] in present_networks:
                        present_networks.append(iface['network_uuid'])

            # Count the requested networks present on this node
            for network in present_networks:
                if network in requested_networks:
                    candidates_network_matches[node] += 1

        # Store candidate nodes keyed by number of matches
        candidates_by_network_matches = {}
        for node in candidates:
            matches = candidates_network_matches[node]
            candidates_by_network_matches.setdefault(matches, []).append(node)

        # Find maximum matches of networks on a node
        max_matches = max(candidates_by_network_matches.keys())

        # Check that the maximum is not just the network node.
        # (Network node always has every network.)
        net_node = db.get_network_node()['fqdn']
        if (max_matches == 1
                and candidates_by_network_matches[max_matches][0] == net_node):
            # No preference, all candidates are a reasonable choice
            return candidates

        # Return list of candidates that has maximum networks
        return candidates_by_network_matches[max_matches]
Esempio n. 2
0
    def place_instance(self, instance, network, candidates=None):
        with util.RecordedOperation('schedule', instance):
            log_ctx = LOG.withObj(instance)

            diff = time.time() - self.metrics_updated
            if diff > config.get('SCHEDULER_CACHE_TIMEOUT'):
                self.refresh_metrics()

            if candidates:
                log_ctx.info('Scheduling %s forced as candidates' % candidates)
                instance.add_event('schedule', 'Forced candidates', None,
                                   str(candidates))
                for node in candidates:
                    if node not in self.metrics:
                        raise exceptions.CandidateNodeNotFoundException(node)
            else:
                candidates = []
                for node in self.metrics.keys():
                    candidates.append(node)
            log_ctx.info('Scheduling %s start as candidates' % candidates)
            instance.add_event('schedule', 'Initial candidates', None,
                               str(candidates))
            if not candidates:
                raise exceptions.LowResourceException('No nodes with metrics')

            # Can we host that many vCPUs?
            for node in copy.copy(candidates):
                max_cpu = self.metrics[node].get('cpu_max_per_instance', 0)
                if instance.cpus > max_cpu:
                    candidates.remove(node)
            log_ctx.info('Scheduling %s have enough actual CPU' % candidates)
            instance.add_event('schedule', 'Have enough actual CPU', None,
                               str(candidates))
            if not candidates:
                raise exceptions.LowResourceException(
                    'Requested vCPUs exceeds vCPU limit')

            # Do we have enough idle CPU?
            for node in copy.copy(candidates):
                if not self._has_sufficient_cpu(instance.cpus, node):
                    candidates.remove(node)
            log_ctx.info('Scheduling %s have enough idle CPU' % candidates)
            instance.add_event('schedule', 'Have enough idle CPU', None,
                               str(candidates))
            if not candidates:
                raise exceptions.LowResourceException(
                    'No nodes with enough idle CPU')

            # Do we have enough idle RAM?
            for node in copy.copy(candidates):
                if not self._has_sufficient_ram(instance.memory, node):
                    candidates.remove(node)
            log_ctx.info('Scheduling %s have enough idle RAM' % candidates)
            instance.add_event('schedule', 'Have enough idle RAM', None,
                               str(candidates))
            if not candidates:
                raise exceptions.LowResourceException(
                    'No nodes with enough idle RAM')

            # Do we have enough idle disk?
            for node in copy.copy(candidates):
                if not self._has_sufficient_disk(instance, node):
                    candidates.remove(node)
            log_ctx.info('Scheduling %s have enough idle disk' % candidates)
            instance.add_event('schedule', 'Have enough idle disk', None,
                               str(candidates))
            if not candidates:
                raise exceptions.LowResourceException(
                    'No nodes with enough disk space')

            # What nodes have the highest number of networks already present?
            if network:
                requested_networks = []
                for net in network:
                    network_uuid = net['network_uuid']
                    if network_uuid not in requested_networks:
                        requested_networks.append(network_uuid)

                candidates = self._find_most_matching_networks(
                    requested_networks, candidates)
                log_ctx.info('Scheduling %s have most matching networks' %
                             candidates)
                instance.add_event('schedule', 'Have most matching networks',
                                   None, str(candidates))

            # What nodes have the base image already?
            requested_images = []
            for disk in instance.block_devices['devices']:
                if disk.get('base'):
                    requested_images = disk.get('base')

            candidates = self._find_most_matching_images(
                requested_images, candidates)
            log_ctx.info('Scheduling %s have most matching images' %
                         candidates)
            instance.add_event('schedule', 'Have most matching images', None,
                               str(candidates))

            # Avoid allocating to network node if possible
            net_node = db.get_network_node()
            if len(candidates) > 1 and net_node['fqdn'] in candidates:
                candidates.remove(net_node['fqdn'])
                log_ctx.info('Scheduling %s are non-network nodes' %
                             candidates)
                instance.add_event('schedule', 'Are non-network nodes', None,
                                   str(candidates))

            # Return a shuffled list of options
            random.shuffle(candidates)
            return candidates