Ejemplo n.º 1
0
    def _event(self):
        """Tries to commit event.

        If there is an event in Climate DB to be done, do it and change its
        status to 'DONE'.
        """
        LOG.debug('Trying to get event from DB.')
        event = db_api.event_get_first_sorted_by_filters(
            sort_key='time',
            sort_dir='asc',
            filters={'status': 'UNDONE'}
        )

        if not event:
            return

        if event['time'] < datetime.datetime.now():
            db_api.event_update(event['id'], {'status': 'IN_PROGRESS'})
            event_type = event['event_type']
            event_fn = getattr(self, event_type, None)
            if event_fn is None:
                raise exceptions.EventError(error='Event type %s is not '
                                                  'supported' % event_type)
            try:
                eventlet.spawn_n(service_utils.with_empty_context(event_fn),
                                 event['lease_id'], event['id'])
                lease = db_api.lease_get(event['lease_id'])
                with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
                    self._send_notification(lease,
                                            ctx,
                                            events=['event.%s' % event_type])
            except Exception:
                db_api.event_update(event['id'], {'status': 'ERROR'})
                LOG.exception(_('Error occurred while event handling.'))
Ejemplo n.º 2
0
    def _event(self):
        """Tries to commit event.

        If there is an event in Climate DB to be done, do it and change its
        status to 'DONE'.
        """
        LOG.debug('Trying to get event from DB.')
        event = db_api.event_get_first_sorted_by_filters(
            sort_key='time',
            sort_dir='asc',
            filters={'status': 'UNDONE'}
        )

        if not event:
            return

        if event['time'] < datetime.datetime.utcnow():
            db_api.event_update(event['id'], {'status': 'IN_PROGRESS'})
            event_type = event['event_type']
            event_fn = getattr(self, event_type, None)
            if event_fn is None:
                raise exceptions.EventError(error='Event type %s is not '
                                                  'supported' % event_type)
            try:
                eventlet.spawn_n(service_utils.with_empty_context(event_fn),
                                 event['lease_id'], event['id'])
                lease = db_api.lease_get(event['lease_id'])
                with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
                    self._send_notification(lease,
                                            ctx,
                                            events=['event.%s' % event_type])
            except Exception:
                db_api.event_update(event['id'], {'status': 'ERROR'})
                LOG.exception(_('Error occurred while event handling.'))
Ejemplo n.º 3
0
    def delete_computehost(self, host_id):
        host = db_api.host_get(host_id)
        if not host:
            raise manager_ex.HostNotFound(host=host_id)

        with trusts.create_ctx_from_trust(host['trust_id']):
            # TODO(sbauza):
            #  - Check if no leases having this host scheduled
            inventory = nova_inventory.NovaInventory()
            servers = inventory.get_servers_per_host(
                host['hypervisor_hostname'])
            if servers:
                raise manager_ex.HostHavingServers(
                    host=host['hypervisor_hostname'], servers=servers)

            try:
                pool = rp.ReservationPool()
                pool.remove_computehost(self.freepool_name,
                                        host['service_name'])
                # NOTE(sbauza): Extracapabilities will be destroyed thanks to
                #  the DB FK.
                db_api.host_destroy(host_id)
            except db_ex.ClimateDBException:
                # Nothing so bad, but we need to advert the admin
                # he has to rerun
                raise manager_ex.CantRemoveHost(host=host_id,
                                                pool=self.freepool_name)
Ejemplo n.º 4
0
    def delete_computehost(self, host_id):
        host = db_api.host_get(host_id)
        if not host:
            raise manager_ex.HostNotFound(host=host_id)

        with trusts.create_ctx_from_trust(host['trust_id']):
            # TODO(sbauza):
            #  - Check if no leases having this host scheduled
            inventory = nova_inventory.NovaInventory()
            servers = inventory.get_servers_per_host(
                host['hypervisor_hostname'])
            if servers:
                raise manager_ex.HostHavingServers(
                    host=host['hypervisor_hostname'], servers=servers)

            try:
                pool = rp.ReservationPool()
                pool.remove_computehost(self.freepool_name,
                                        host['service_name'])
                # NOTE(sbauza): Extracapabilities will be destroyed thanks to
                #  the DB FK.
                db_api.host_destroy(host_id)
            except db_ex.ClimateDBException:
                # Nothing so bad, but we need to advert the admin
                # he has to rerun
                raise manager_ex.CantRemoveHost(host=host_id,
                                                pool=self.freepool_name)
Ejemplo n.º 5
0
 def delete_lease(self, lease_id):
     lease = self.get_lease(lease_id)
     if (datetime.datetime.utcnow() < lease['start_date'] or
             datetime.datetime.utcnow() > lease['end_date']):
         with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
             for reservation in lease['reservations']:
                 plugin = self.plugins[reservation['resource_type']]
                 try:
                     plugin.on_end(reservation['resource_id'])
                 except (db_ex.ClimateDBException, RuntimeError):
                     error_msg = "Failed to delete a reservation for a lease."
                     lease_state = states.LeaseState(id=lease_id,
                             action=states.lease.DELETE,
                             status=states.lease.FAILED,
                             status_reason=error_msg)
                     lease_state.save()
                     LOG.exception(error_msg)
                     raise
             db_api.lease_destroy(lease_id)
             self._send_notification(lease, ctx, events=['delete'])
     else:
         error_msg = "Already started lease cannot be deleted"
         lease_state = states.LeaseState(id=lease_id,
                 action=states.lease.DELETE,
                 status=states.lease.FAILED,
                 status_reason=error_msg)
         lease_state.save()
         raise common_ex.NotAuthorized(error_msg)
Ejemplo n.º 6
0
 def delete_lease(self, lease_id):
     lease = self.get_lease(lease_id)
     if (datetime.datetime.now() < lease['start_date'] or
             datetime.datetime.now() > lease['end_date']):
         with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
             for reservation in lease['reservations']:
                 plugin = self.plugins[reservation['resource_type']]
                 try:
                     plugin.on_end(reservation['resource_id'])
                 except (db_ex.ClimateDBException, RuntimeError):
                     LOG.exception("Failed to delete a reservation "
                                   "for a lease.")
                     raise
             db_api.lease_destroy(lease_id)
             self._send_notification(lease, ctx, events=['delete'])
     else:
         raise common_ex.NotAuthorized(
             'Already started lease cannot be deleted')
Ejemplo n.º 7
0
 def delete_lease(self, lease_id):
     lease = self.get_lease(lease_id)
     if (datetime.datetime.utcnow() < lease['start_date']
             or datetime.datetime.utcnow() > lease['end_date']):
         with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
             for reservation in lease['reservations']:
                 plugin = self.plugins[reservation['resource_type']]
                 try:
                     plugin.on_end(reservation['resource_id'])
                 except (db_ex.ClimateDBException, RuntimeError):
                     LOG.exception("Failed to delete a reservation "
                                   "for a lease.")
                     raise
             db_api.lease_destroy(lease_id)
             self._send_notification(lease, ctx, events=['delete'])
     else:
         raise common_ex.NotAuthorized(
             'Already started lease cannot be deleted')
Ejemplo n.º 8
0
    def update_lease(self, lease_id, values):
        if not values:
            return db_api.lease_get(lease_id)

        if len(values) == 1 and 'name' in values:
            db_api.lease_update(lease_id, values)
            return db_api.lease_get(lease_id)

        lease = db_api.lease_get(lease_id)
        start_date = values.get(
            'start_date',
            datetime.datetime.strftime(lease['start_date'], LEASE_DATE_FORMAT))
        end_date = values.get(
            'end_date',
            datetime.datetime.strftime(lease['end_date'], LEASE_DATE_FORMAT))
        before_end_date = values.get('before_end_notification', None)

        now = datetime.datetime.now()
        now = datetime.datetime(now.year,
                                now.month,
                                now.day,
                                now.hour,
                                now.minute)
        if start_date == 'now':
            start_date = now
        else:
            start_date = self._date_from_string(start_date)
        end_date = self._date_from_string(end_date)

        values['start_date'] = start_date
        values['end_date'] = end_date

        if (lease['start_date'] < now and
                values['start_date'] != lease['start_date']):
            raise common_ex.NotAuthorized(
                'Cannot modify the start date of already started leases')

        if (lease['start_date'] > now and
                values['start_date'] < now):
            raise common_ex.NotAuthorized(
                'Start date must later than current date')

        if lease['end_date'] < now:
            raise common_ex.NotAuthorized(
                'Terminated leases can only be renamed')

        if (values['end_date'] < now or
           values['end_date'] < values['start_date']):
            raise common_ex.NotAuthorized(
                'End date must be later than current and start date')

        with trusts.create_ctx_from_trust(lease['trust_id']):
            if before_end_date:
                try:
                    before_end_date = self._date_from_string(before_end_date)
                    self._check_date_within_lease_limits(before_end_date,
                                                         values)
                except common_ex.ClimateException as e:
                    LOG.error("Invalid before_end_date param. %s" % e.message)
                    raise e

            # TODO(frossigneux) rollback if an exception is raised
            for reservation in (
                    db_api.reservation_get_all_by_lease_id(lease_id)):
                reservation['start_date'] = values['start_date']
                reservation['end_date'] = values['end_date']
                resource_type = reservation['resource_type']
                self.plugins[resource_type].update_reservation(
                    reservation['id'],
                    reservation)

        event = db_api.event_get_first_sorted_by_filters(
            'lease_id',
            'asc',
            {
                'lease_id': lease_id,
                'event_type': 'start_lease'
            }
        )
        if not event:
            raise common_ex.ClimateException(
                'Start lease event not found')
        db_api.event_update(event['id'], {'time': values['start_date']})

        event = db_api.event_get_first_sorted_by_filters(
            'lease_id',
            'asc',
            {
                'lease_id': lease_id,
                'event_type': 'end_lease'
            }
        )
        if not event:
            raise common_ex.ClimateException(
                'End lease event not found')
        db_api.event_update(event['id'], {'time': values['end_date']})

        notifications = ['update']
        self._update_before_end_event(lease, values, notifications,
                                      before_end_date)

        db_api.lease_update(lease_id, values)

        lease = db_api.lease_get(lease_id)
        with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
            self._send_notification(lease, ctx, events=notifications)

        return lease
Ejemplo n.º 9
0
    def create_lease(self, lease_values):
        """Create a lease with reservations.

        Return either the model of created lease or None if any error.
        """
        try:
            trust_id = lease_values.pop('trust_id')
        except KeyError:
            raise exceptions.MissingTrustId()

        # Remove and keep reservation values
        reservations = lease_values.pop("reservations", [])

        # Create the lease without the reservations
        start_date = lease_values['start_date']
        end_date = lease_values['end_date']

        now = datetime.datetime.now()
        now = datetime.datetime(now.year,
                                now.month,
                                now.day,
                                now.hour,
                                now.minute)
        if start_date == 'now':
            start_date = now
        else:
            start_date = self._date_from_string(start_date)
        end_date = self._date_from_string(end_date)

        if start_date < now:
            raise common_ex.NotAuthorized(
                'Start date must later than current date')

        with trusts.create_ctx_from_trust(trust_id) as ctx:
            lease_values['user_id'] = ctx.user_id
            lease_values['project_id'] = ctx.project_id
            lease_values['start_date'] = start_date
            lease_values['end_date'] = end_date

            if not lease_values.get('events'):
                lease_values['events'] = []

            lease_values['events'].append({'event_type': 'start_lease',
                                           'time': start_date,
                                           'status': 'UNDONE'})
            lease_values['events'].append({'event_type': 'end_lease',
                                           'time': end_date,
                                           'status': 'UNDONE'})

            before_end_date = lease_values.get('before_end_notification', None)
            if before_end_date:
                # incoming param. Validation check
                try:
                    before_end_date = self._date_from_string(
                        before_end_date)
                    self._check_date_within_lease_limits(before_end_date,
                                                         lease_values)
                except common_ex.ClimateException as e:
                    LOG.error("Invalid before_end_date param. %s" % e.message)
                    raise e
            elif CONF.manager.notify_hours_before_lease_end > 0:
                delta = datetime.timedelta(
                    hours=CONF.manager.notify_hours_before_lease_end)
                before_end_date = lease_values['end_date'] - delta

            if before_end_date:
                event = {'event_type': 'before_end_lease',
                         'status': 'UNDONE'}
                lease_values['events'].append(event)
                self._update_before_end_event_date(event, before_end_date,
                                                   lease_values)

            try:
                if trust_id:
                    lease_values.update({'trust_id': trust_id})
                lease = db_api.lease_create(lease_values)
                lease_id = lease['id']
            except db_ex.ClimateDBDuplicateEntry:
                LOG.exception('Cannot create a lease - duplicated lease name')
                raise exceptions.LeaseNameAlreadyExists(
                    name=lease_values['name'])
            except db_ex.ClimateDBException:
                LOG.exception('Cannot create a lease')
                raise
            else:
                try:
                    for reservation in reservations:
                        reservation['lease_id'] = lease['id']
                        reservation['start_date'] = lease['start_date']
                        reservation['end_date'] = lease['end_date']
                        resource_type = reservation['resource_type']
                        if resource_type in self.plugins:
                            self.plugins[resource_type].create_reservation(
                                reservation)
                        else:
                            raise exceptions.UnsupportedResourceType(
                                resource_type)
                except (exceptions.UnsupportedResourceType,
                        common_ex.ClimateException):
                    LOG.exception("Failed to create reservation for a lease. "
                                  "Rollback the lease and associated "
                                  "reservations")
                    db_api.lease_destroy(lease_id)
                    raise

                else:
                    lease = db_api.lease_get(lease['id'])
                    self._send_notification(lease, ctx, events=['create'])
                    return lease
Ejemplo n.º 10
0
 def end_lease(self, lease_id, event_id):
     lease = self.get_lease(lease_id)
     with trusts.create_ctx_from_trust(lease['trust_id']):
         self._basic_action(lease_id, event_id, 'on_end', 'deleted')
Ejemplo n.º 11
0
 def start_lease(self, lease_id, event_id):
     lease = self.get_lease(lease_id)
     with trusts.create_ctx_from_trust(lease['trust_id']):
         self._basic_action(lease_id, event_id, 'on_start', 'active')
Ejemplo n.º 12
0
    def update_lease(self, lease_id, values):
        if not values:
            return db_api.lease_get(lease_id)

        if len(values) == 1 and 'name' in values:
            db_api.lease_update(lease_id, values)
            return db_api.lease_get(lease_id)

        lease = db_api.lease_get(lease_id)
        start_date = values.get(
            'start_date',
            datetime.datetime.strftime(lease['start_date'], LEASE_DATE_FORMAT))
        end_date = values.get(
            'end_date',
            datetime.datetime.strftime(lease['end_date'], LEASE_DATE_FORMAT))
        before_end_date = values.get('before_end_notification', None)

        now = datetime.datetime.utcnow()
        now = datetime.datetime(now.year,
                                now.month,
                                now.day,
                                now.hour,
                                now.minute)
        if start_date == 'now':
            start_date = now
        else:
            start_date = self._date_from_string(start_date)
        end_date = self._date_from_string(end_date)

        values['start_date'] = start_date
        values['end_date'] = end_date

        if (lease['start_date'] < now and
                values['start_date'] != lease['start_date']):
            raise common_ex.NotAuthorized(
                'Cannot modify the start date of already started leases')

        if (lease['start_date'] > now and
                values['start_date'] < now):
            raise common_ex.NotAuthorized(
                'Start date must later than current date')

        if lease['end_date'] < now:
            raise common_ex.NotAuthorized(
                'Terminated leases can only be renamed')

        if (values['end_date'] < now or
           values['end_date'] < values['start_date']):
            raise common_ex.NotAuthorized(
                'End date must be later than current and start date')

        with trusts.create_ctx_from_trust(lease['trust_id']):
            if before_end_date:
                try:
                    before_end_date = self._date_from_string(before_end_date)
                    self._check_date_within_lease_limits(before_end_date,
                                                         values)
                except common_ex.ClimateException as e:
                    LOG.error("Invalid before_end_date param. %s" % e.message)
                    raise e

            # TODO(frossigneux) rollback if an exception is raised
            for reservation in (
                    db_api.reservation_get_all_by_lease_id(lease_id)):
                reservation['start_date'] = values['start_date']
                reservation['end_date'] = values['end_date']
                resource_type = reservation['resource_type']
                self.plugins[resource_type].update_reservation(
                    reservation['id'],
                    reservation)

        event = db_api.event_get_first_sorted_by_filters(
            'lease_id',
            'asc',
            {
                'lease_id': lease_id,
                'event_type': 'start_lease'
            }
        )
        if not event:
            raise common_ex.ClimateException(
                'Start lease event not found')
        db_api.event_update(event['id'], {'time': values['start_date']})

        event = db_api.event_get_first_sorted_by_filters(
            'lease_id',
            'asc',
            {
                'lease_id': lease_id,
                'event_type': 'end_lease'
            }
        )
        if not event:
            raise common_ex.ClimateException(
                'End lease event not found')
        db_api.event_update(event['id'], {'time': values['end_date']})

        notifications = ['update']
        self._update_before_end_event(lease, values, notifications,
                                      before_end_date)

        db_api.lease_update(lease_id, values)

        lease_state = states.LeaseState(id=lease_id,
                action=states.lease.UPDATE,
                status=states.lease.COMPLETE,
                status_reason="Successfully updated lease")
        lease_state.save()
        lease = db_api.lease_get(lease_id)
        with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
            self._send_notification(lease, ctx, events=notifications)

        return lease
Ejemplo n.º 13
0
    def create_lease(self, lease_values):
        """Create a lease with reservations.

        Return either the model of created lease or None if any error.
        """
        try:
            trust_id = lease_values.pop('trust_id')
        except KeyError:
            raise exceptions.MissingTrustId()

        # Remove and keep reservation values
        reservations = lease_values.pop("reservations", [])

        # Create the lease without the reservations
        start_date = lease_values['start_date']
        end_date = lease_values['end_date']

        now = datetime.datetime.utcnow()
        now = datetime.datetime(now.year,
                                now.month,
                                now.day,
                                now.hour,
                                now.minute)
        if start_date == 'now':
            start_date = now
        else:
            start_date = self._date_from_string(start_date)
        end_date = self._date_from_string(end_date)

        if start_date < now:
            raise common_ex.NotAuthorized(
                'Start date must later than current date')

        with trusts.create_ctx_from_trust(trust_id) as ctx:
            lease_values['user_id'] = ctx.user_id
            lease_values['project_id'] = ctx.project_id
            lease_values['start_date'] = start_date
            lease_values['end_date'] = end_date

            if not lease_values.get('events'):
                lease_values['events'] = []

            lease_values['events'].append({'event_type': 'start_lease',
                                           'time': start_date,
                                           'status': 'UNDONE'})
            lease_values['events'].append({'event_type': 'end_lease',
                                           'time': end_date,
                                           'status': 'UNDONE'})

            before_end_date = lease_values.get('before_end_notification', None)
            if before_end_date:
                # incoming param. Validation check
                try:
                    before_end_date = self._date_from_string(
                        before_end_date)
                    self._check_date_within_lease_limits(before_end_date,
                                                         lease_values)
                except common_ex.ClimateException as e:
                    LOG.error("Invalid before_end_date param. %s" % e.message)
                    raise e
            elif CONF.manager.notify_hours_before_lease_end > 0:
                delta = datetime.timedelta(
                    hours=CONF.manager.notify_hours_before_lease_end)
                before_end_date = lease_values['end_date'] - delta

            if before_end_date:
                event = {'event_type': 'before_end_lease',
                         'status': 'UNDONE'}
                lease_values['events'].append(event)
                self._update_before_end_event_date(event, before_end_date,
                                                   lease_values)

            try:
                if trust_id:
                    lease_values.update({'trust_id': trust_id})
                lease = db_api.lease_create(lease_values)
                lease_id = lease['id']
            except db_ex.ClimateDBDuplicateEntry:
                LOG.exception('Cannot create a lease - duplicated lease name')
                raise exceptions.LeaseNameAlreadyExists(
                    name=lease_values['name'])
            except db_ex.ClimateDBException:
                LOG.exception('Cannot create a lease')
                raise
            else:
                try:
                    for reservation in reservations:
                        reservation['lease_id'] = lease['id']
                        reservation['start_date'] = lease['start_date']
                        reservation['end_date'] = lease['end_date']
                        resource_type = reservation['resource_type']
                        if resource_type in self.plugins:
                            self.plugins[resource_type].create_reservation(
                                reservation)
                        else:
                            raise exceptions.UnsupportedResourceType(
                                resource_type)
                except (exceptions.UnsupportedResourceType,
                        common_ex.ClimateException):
                    LOG.exception("Failed to create reservation for a lease. "
                                  "Rollback the lease and associated "
                                  "reservations")
                    db_api.lease_destroy(lease_id)
                    raise

                else:
                    lease_state = states.LeaseState(id=lease['id'],
                            action=states.lease.CREATE,
                            status=states.lease.COMPLETE,
                            status_reason="Successfully created lease")
                    lease_state.save()
                    lease = db_api.lease_get(lease['id'])
                    self._send_notification(lease, ctx, events=['create'])
                    return lease
Ejemplo n.º 14
0
    def create_computehost(self, host_values):
        # TODO(sbauza):
        #  - Exception handling for HostNotFound
        host_id = host_values.pop('id', None)
        host_name = host_values.pop('name', None)
        try:
            trust_id = host_values.pop('trust_id')
        except KeyError:
            raise manager_ex.MissingTrustId()

        host_ref = host_id or host_name
        if host_ref is None:
            raise manager_ex.InvalidHost(host=host_values)

        with trusts.create_ctx_from_trust(trust_id):
            inventory = nova_inventory.NovaInventory()
            servers = inventory.get_servers_per_host(host_ref)
            if servers:
                raise manager_ex.HostHavingServers(host=host_ref,
                                                   servers=servers)
            host_details = inventory.get_host_details(host_ref)
            # NOTE(sbauza): Only last duplicate name for same extra capability
            # will be stored
            to_store = set(host_values.keys()) - set(host_details.keys())
            extra_capabilities_keys = to_store
            extra_capabilities = dict(
                (key, host_values[key]) for key in extra_capabilities_keys
            )
            pool = rp.ReservationPool()
            pool.add_computehost(self.freepool_name,
                                 host_details['service_name'])

            host = None
            cantaddextracapability = []
            try:
                if trust_id:
                    host_details.update({'trust_id': trust_id})
                host = db_api.host_create(host_details)
            except db_ex.ClimateDBException:
                # We need to rollback
                # TODO(sbauza): Investigate use of Taskflow for atomic
                # transactions
                pool.remove_computehost(self.freepool_name,
                                        host_details['service_name'])
            if host:
                for key in extra_capabilities:
                    values = {'computehost_id': host['id'],
                              'capability_name': key,
                              'capability_value': extra_capabilities[key],
                              }
                    try:
                        db_api.host_extra_capability_create(values)
                    except db_ex.ClimateDBException:
                        cantaddextracapability.append(key)
            if cantaddextracapability:
                raise manager_ex.CantAddExtraCapability(
                    keys=cantaddextracapability,
                    host=host['id'])
            if host:
                return self.get_computehost(host['id'])
            else:
                return None
Ejemplo n.º 15
0
 def start_lease(self, lease_id, event_id):
     lease = self.get_lease(lease_id)
     with trusts.create_ctx_from_trust(lease['trust_id']):
         self._basic_action(lease_id, event_id, 'on_start', 'active')
Ejemplo n.º 16
0
 def end_lease(self, lease_id, event_id):
     lease = self.get_lease(lease_id)
     with trusts.create_ctx_from_trust(lease['trust_id']):
         self._basic_action(lease_id, event_id, 'on_end', 'deleted')
Ejemplo n.º 17
0
    def create_computehost(self, host_values):
        # TODO(sbauza):
        #  - Exception handling for HostNotFound
        host_id = host_values.pop('id', None)
        host_name = host_values.pop('name', None)
        try:
            trust_id = host_values.pop('trust_id')
        except KeyError:
            raise manager_ex.MissingTrustId()

        host_ref = host_id or host_name
        if host_ref is None:
            raise manager_ex.InvalidHost(host=host_values)

        with trusts.create_ctx_from_trust(trust_id):
            inventory = nova_inventory.NovaInventory()
            servers = inventory.get_servers_per_host(host_ref)
            if servers:
                raise manager_ex.HostHavingServers(host=host_ref,
                                                   servers=servers)
            host_details = inventory.get_host_details(host_ref)
            # NOTE(sbauza): Only last duplicate name for same extra capability
            # will be stored
            to_store = set(host_values.keys()) - set(host_details.keys())
            extra_capabilities_keys = to_store
            extra_capabilities = dict(
                (key, host_values[key]) for key in extra_capabilities_keys
            )
            pool = rp.ReservationPool()
            pool.add_computehost(self.freepool_name,
                                 host_details['service_name'])

            host = None
            cantaddextracapability = []
            try:
                if trust_id:
                    host_details.update({'trust_id': trust_id})
                host = db_api.host_create(host_details)
            except db_ex.ClimateDBException:
                # We need to rollback
                # TODO(sbauza): Investigate use of Taskflow for atomic
                # transactions
                pool.remove_computehost(self.freepool_name,
                                        host_details['service_name'])
            if host:
                for key in extra_capabilities:
                    values = {'computehost_id': host['id'],
                              'capability_name': key,
                              'capability_value': extra_capabilities[key],
                              }
                    try:
                        db_api.host_extra_capability_create(values)
                    except db_ex.ClimateDBException:
                        cantaddextracapability.append(key)
            if cantaddextracapability:
                raise manager_ex.CantAddExtraCapability(
                    keys=cantaddextracapability,
                    host=host['id'])
            if host:
                return self.get_computehost(host['id'])
            else:
                return None