コード例 #1
0
    def _matching_hosts(self, hypervisor_properties, resource_properties,
                        count_range, start_date, end_date):
        """Return the matching hosts (preferably not allocated)

        """
        count_range = count_range.split('-')
        min_host = count_range[0]
        max_host = count_range[1]
        allocated_host_ids = []
        not_allocated_host_ids = []
        filter_array = []
        start_date_with_margin = start_date - datetime.timedelta(
            minutes=CONF.cleaning_time)
        end_date_with_margin = end_date + datetime.timedelta(
            minutes=CONF.cleaning_time)

        # TODO(frossigneux) support "or" operator
        if hypervisor_properties:
            filter_array = plugins_utils.convert_requirements(
                hypervisor_properties)
        if resource_properties:
            filter_array += plugins_utils.convert_requirements(
                resource_properties)
        for host in db_api.reservable_host_get_all_by_queries(filter_array):
            if not db_api.host_allocation_get_all_by_values(
                    compute_host_id=host['id']):
                not_allocated_host_ids.append(host['id'])
            elif db_utils.get_free_periods(
                    host['id'], start_date_with_margin, end_date_with_margin,
                    end_date_with_margin - start_date_with_margin) == [
                        (start_date_with_margin, end_date_with_margin),
                    ]:
                allocated_host_ids.append(host['id'])
        if len(not_allocated_host_ids) >= int(min_host):
            return not_allocated_host_ids[:int(max_host)]
        all_host_ids = allocated_host_ids + not_allocated_host_ids
        if len(all_host_ids) >= int(min_host):
            return all_host_ids[:int(max_host)]
        else:
            return []
コード例 #2
0
    def update_host_allocations(self, added, removed, reservation_id):
        allocations = db_api.host_allocation_get_all_by_values(
            reservation_id=reservation_id)

        removed_allocs = []
        for host_id in removed:
            for allocation in allocations:
                if allocation['compute_host_id'] == host_id:
                    removed_allocs.append(allocation['id'])
                    break

        # TODO(tetsuro): It would be nice to have something like
        # db_api.host_allocation_replace() to process the following
        # deletion and addition in *one* DB transaction.
        for alloc_id in removed_allocs:
            db_api.host_allocation_destroy(alloc_id)

        for added_host in added:
            db_api.host_allocation_create({
                'compute_host_id': added_host,
                'reservation_id': reservation_id
            })
コード例 #3
0
    def update_resources(self, reservation_id):
        """Updates reserved resources in Nova.

        This method updates reserved resources in Compute service. If the
        reservation is in active status, it adds new allocated hosts into
        a reserved aggregate. If the reservation is not started yet, it
        updates a reserved flavor.
        """
        reservation = db_api.reservation_get(reservation_id)

        if reservation['status'] == 'active':
            pool = nova.ReservationPool()
            for allocation in db_api.host_allocation_get_all_by_values(
                    reservation_id=reservation['id']):
                host = db_api.host_get(allocation['compute_host_id'])
                try:
                    pool.add_computehost(
                        reservation['aggregate_id'],
                        host['service_name'], stay_in=True)
                except mgr_exceptions.AggregateAlreadyHasHost:
                    pass
                except nova_exceptions.ClientException:
                    err_msg = ('Fail to add host %s to aggregate %s.'
                               % (host, reservation['aggregate_id']))
                    raise mgr_exceptions.NovaClientError(err_msg)
                self.placement_client.update_reservation_inventory(
                    host['service_name'], reservation['id'], 1)
        else:
            try:
                self.nova.nova.flavors.delete(reservation['id'])
                self._create_flavor(reservation['id'],
                                    reservation['vcpus'],
                                    reservation['memory_mb'],
                                    reservation['disk_gb'],
                                    reservation['server_group_id'])
            except nova_exceptions.ClientException:
                LOG.exception("Failed to update Nova resources "
                              "for reservation %s", reservation['id'])
                raise mgr_exceptions.NovaClientError()
コード例 #4
0
    def on_start(self, resource_id):
        ctx = context.current()
        instance_reservation = db_api.instance_reservation_get(resource_id)
        reservation_id = instance_reservation['reservation_id']

        try:
            self.nova.flavor_access.add_tenant_access(reservation_id,
                                                      ctx.project_id)
        except nova_exceptions.ClientException:
            LOG.info('Failed to associate flavor %(reservation_id)s '
                     'to project %(project_id)s',
                     {'reservation_id': reservation_id,
                      'project_id': ctx.project_id})
            raise mgr_exceptions.EventError()

        pool = nova.ReservationPool()
        for allocation in db_api.host_allocation_get_all_by_values(
                reservation_id=reservation_id):
            host = db_api.host_get(allocation['compute_host_id'])
            pool.add_computehost(instance_reservation['aggregate_id'],
                                 host['service_name'], stay_in=True)
            self.placement_client.update_reservation_inventory(
                host['service_name'], reservation_id, 1)
コード例 #5
0
 def on_end(self, resource_id):
     """Remove the hosts from the pool."""
     host_reservation = db_api.host_reservation_get(resource_id)
     db_api.host_reservation_update(host_reservation['id'],
                                    {'status': 'completed'})
     allocations = db_api.host_allocation_get_all_by_values(
         reservation_id=host_reservation['reservation_id'])
     for allocation in allocations:
         db_api.host_allocation_destroy(allocation['id'])
     pool = nova.ReservationPool()
     for host in pool.get_computehosts(host_reservation['aggregate_id']):
         for server in self.nova.servers.list(
                 search_opts={"host": host, "all_tenants": 1}):
             try:
                 self.nova.servers.delete(server=server)
             except nova_exceptions.NotFound:
                 LOG.info('Could not find server %s, may have been deleted '
                          'concurrently.', server)
             except Exception as e:
                 LOG.exception('Failed to delete %s: %s.', server, str(e))
     try:
         pool.delete(host_reservation['aggregate_id'])
     except manager_ex.AggregateNotFound:
         pass
コード例 #6
0
    def pickup_hosts(self, reservation_id, values):
        """Returns lists of host ids to add/remove.

        This function picks up available hosts, calculates the difference from
        old reservations and returns a dict of a list of host ids to add
        and remove keyed by "added" or "removed".

        Note that the lists allow duplicated host ids for `affinity=True`
        cases.

        :raises: NotEnoughHostsAvailable exception if there are not enough
                 hosts available for the request
        """
        req_amount = values['amount']
        affinity = bool_from_string(values['affinity'], default=None)

        query_params = {
            'cpus': values['vcpus'],
            'memory': values['memory_mb'],
            'disk': values['disk_gb'],
            'resource_properties': values['resource_properties'],
            'start_date': values['start_date'],
            'end_date': values['end_date']
        }

        old_allocs = db_api.host_allocation_get_all_by_values(
            reservation_id=reservation_id)
        if old_allocs:
            # This is a path for *update* reservation. Add the specific
            # query param not to consider resources reserved by existing
            # reservations to update
            query_params['excludes_res'] = [reservation_id]

        new_hosts = self.query_available_hosts(**query_params)

        old_host_id_list = [h['compute_host_id'] for h in old_allocs]
        candidate_id_list = [h['id'] for h in new_hosts]

        # Build `new_host_id_list`. Note that we'd like to pick up hosts in
        # the following order of priority:
        #  1. hosts reserved by the reservation to update
        #  2. hosts with reservations followed by hosts without reservations
        # Note that the `candidate_id_list` has already been ordered
        # satisfying the second requirement.
        if affinity:
            host_id_map = collections.Counter(candidate_id_list)
            available = {k for k, v in host_id_map.items() if v >= req_amount}
            if not available:
                raise mgr_exceptions.NotEnoughHostsAvailable()
            new_host_ids = set(old_host_id_list) & available
            if new_host_ids:
                # (priority 1) This is a path for update reservation. We pick
                # up a host from hosts reserved by the reservation to update.
                new_host_id = new_host_ids.pop()
            else:
                # (priority 2) This is a path both for update and for new
                # reservation. We pick up hosts with some other reservations
                # if possible and otherwise pick up hosts without any
                # reservation. We can do so by considering the order of the
                # `candidate_id_list`.
                for host_id in candidate_id_list:
                    if host_id in available:
                        new_host_id = host_id
                        break
            new_host_id_list = [new_host_id] * req_amount
        else:
            # Hosts that can accommodate but don't satisfy priority 1
            _, possible_host_list = plugins_utils.list_difference(
                old_host_id_list, candidate_id_list)
            # Hosts that satisfy priority 1
            new_host_id_list, _ = plugins_utils.list_difference(
                candidate_id_list, possible_host_list)
            if affinity is False:
                # Eliminate the duplication
                new_host_id_list = list(set(new_host_id_list))
            for host_id in possible_host_list:
                if (affinity is False) and (host_id in new_host_id_list):
                    # Eliminate the duplication
                    continue
                new_host_id_list.append(host_id)
            if len(new_host_id_list) < req_amount:
                raise mgr_exceptions.NotEnoughHostsAvailable()
            while len(new_host_id_list) > req_amount:
                new_host_id_list.pop()

        # Calculate the difference from the existing reserved host
        removed_host_ids, added_host_ids = plugins_utils.list_difference(
            old_host_id_list, new_host_id_list)

        return {'added': added_host_ids, 'removed': removed_host_ids}
コード例 #7
0
ファイル: host_plugin.py プロジェクト: souvilleb/blazar
    def heal_reservations(self, failed_resources):
        """Heal reservations which suffer from resource failures.

        :param: failed_resources: a list of failed hosts.
        :return: a dictionary of {reservation id: flags to update}
                 e.g. {'de27786d-bd96-46bb-8363-19c13b2c6657':
                       {'missing_resources': True}}
        """
        reservation_flags = {}

        failed_allocs = []
        for host in failed_resources:
            failed_allocs += db_api.host_allocation_get_all_by_values(
                compute_host_id=host['id'])

        for alloc in failed_allocs:
            reservation = db_api.reservation_get(alloc['reservation_id'])
            if reservation['resource_type'] != plugin.RESOURCE_TYPE:
                continue
            lease = db_api.lease_get(reservation['lease_id'])
            host_reservation = None
            pool = None

            # Remove the failed host from the aggregate.
            if reservation['status'] == status.reservation.ACTIVE:
                host = db_api.host_get(alloc['compute_host_id'])
                host_reservation = db_api.host_reservation_get(
                    reservation['resource_id'])
                with trusts.create_ctx_from_trust(lease['trust_id']):
                    pool = nova.ReservationPool()
                    pool.remove_computehost(host_reservation['aggregate_id'],
                                            host['service_name'])

            # Allocate alternative resource.
            start_date = max(datetime.datetime.utcnow(), lease['start_date'])
            new_hostids = self._matching_hosts(
                reservation['hypervisor_properties'],
                reservation['resource_properties'], '1-1', start_date,
                lease['end_date'])
            if not new_hostids:
                if reservation['id'] not in reservation_flags:
                    reservation_flags[reservation['id']] = {}
                reservation_flags[reservation['id']].update(
                    {'missing_resources': True})
                db_api.host_allocation_destroy(alloc['id'])
                LOG.warn(
                    'Could not find alternative host for reservation %s '
                    '(lease: %s).', reservation['id'], lease['name'])
            else:
                new_hostid = new_hostids.pop()
                db_api.host_allocation_update(alloc['id'],
                                              {'compute_host_id': new_hostid})
                if reservation['status'] == status.reservation.ACTIVE:
                    # Add the alternative host into the aggregate.
                    new_host = db_api.host_get(new_hostid)
                    with trusts.create_ctx_from_trust(lease['trust_id']):
                        pool.add_computehost(host_reservation['aggregate_id'],
                                             new_host['service_name'])
                    if reservation['id'] not in reservation_flags:
                        reservation_flags[reservation['id']] = {}
                    reservation_flags[reservation['id']].update(
                        {'resources_changed': True})
                LOG.warn('Resource changed for reservation %s (lease: %s).',
                         reservation['id'], lease['name'])

        return reservation_flags
コード例 #8
0
ファイル: instance_plugin.py プロジェクト: souvilleb/blazar
    def heal_reservations(self, failed_resources):
        """Heal reservations which suffer from resource failures.

        :param: failed_resources: a list of failed hosts.
        :return: a dictionary of {reservation id: flags to update}
                 e.g. {'de27786d-bd96-46bb-8363-19c13b2c6657':
                       {'missing_resources': True}}
        """
        reservation_flags = {}

        failed_allocs = []
        for host in failed_resources:
            failed_allocs += db_api.host_allocation_get_all_by_values(
                compute_host_id=host['id'])

        for alloc in failed_allocs:
            reservation = db_api.reservation_get(alloc['reservation_id'])
            if reservation['resource_type'] != RESOURCE_TYPE:
                continue
            pool = None

            # Remove the failed host from the aggregate.
            if reservation['status'] == status.reservation.ACTIVE:
                host = db_api.host_get(alloc['compute_host_id'])
                pool = nova.ReservationPool()
                pool.remove_computehost(reservation['aggregate_id'],
                                        host['service_name'])

            # Allocate alternative resource.
            values = {}
            lease = db_api.lease_get(reservation['lease_id'])
            values['start_date'] = max(datetime.datetime.utcnow(),
                                       lease['start_date'])
            values['end_date'] = lease['end_date']
            specs = ['vcpus', 'memory_mb', 'disk_gb', 'affinity', 'amount']
            for key in specs:
                values[key] = reservation[key]
            changed_hosts = self.pickup_hosts(reservation['id'], values)
            if len(changed_hosts['added']) == 0:
                if reservation['id'] not in reservation_flags:
                    reservation_flags[reservation['id']] = {}
                reservation_flags[reservation['id']].update(
                    {'missing_resources': True})
                db_api.host_allocation_destroy(alloc['id'])
                LOG.warn(
                    'Could not find alternative host for reservation %s '
                    '(lease: %s).', reservation['id'], lease['name'])
            else:
                new_host_id = changed_hosts['added'].pop()
                db_api.host_allocation_update(alloc['id'],
                                              {'compute_host_id': new_host_id})
                if reservation['status'] == status.reservation.ACTIVE:
                    # Add the alternative host into the aggregate.
                    new_host = db_api.host_get(new_host_id)
                    pool.add_computehost(reservation['aggregate_id'],
                                         new_host['service_name'],
                                         stay_in=True)
                    if reservation['id'] not in reservation_flags:
                        reservation_flags[reservation['id']] = {}
                    reservation_flags[reservation['id']].update(
                        {'resources_changed': True})

                LOG.warn('Resource changed for reservation %s (lease: %s).',
                         reservation['id'], lease['name'])

        return reservation_flags