예제 #1
0
    def test_check_update_with_exception(self):
        lease, rsv, allocs = get_lease_rsv_allocs()

        new_lease_values = get_fake_lease(end_date='2014-02-07 13:37')
        new_reservations = list(new_lease_values['reservations'])
        allocation_candidates = {'virtual:instance': [get_fake_host('2')]}

        del new_lease_values['reservations']
        ctx = context.current()

        check_update = self.patch(self.enforcement.enabled_filters[0],
                                  'check_update')
        check_update.side_effect = exceptions.BlazarException

        self.assertRaises(exceptions.BlazarException,
                          self.enforcement.check_update,
                          context=ctx,
                          current_lease=lease,
                          new_lease=new_lease_values,
                          current_allocations=allocs,
                          new_allocations=allocation_candidates,
                          current_reservations=rsv,
                          new_reservations=new_reservations)
예제 #2
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)
예제 #3
0
    def test_on_end(self):
        allocations = {'virtual:instance': [get_fake_host('1')]}
        lease = get_fake_lease()
        ctx = context.current()

        on_end = self.patch(self.enforcement.enabled_filters[0], 'on_end')

        self.enforcement.on_end(ctx, lease, allocations)

        formatted_context = self.enforcement.format_context(ctx, lease)
        formatted_lease = self.enforcement.format_lease(
            lease, lease['reservations'], allocations)

        on_end.assert_called_once_with(formatted_context, formatted_lease)

        expected_context = dict(user_id='111',
                                project_id='222',
                                region_name=self.region,
                                auth_url='https://fakeauth.com')

        expected_lease = self.get_formatted_lease(lease, None, allocations)

        self.assertDictEqual(expected_context, formatted_context)
        self.assertDictEqual(expected_lease, formatted_lease)
예제 #4
0
파일: service.py 프로젝트: stackhpc/blazar
    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_date', None)

        start_date, end_date, now = self._parse_lease_dates(start_date,
                                                            end_date)

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

        self._check_for_invalid_date_inputs(lease, values, now)

        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.BlazarException as e:
                    LOG.error("Invalid before_end_date param. %s", str(e))
                    raise e

            reservations = values.get('reservations', [])
            existing_reservations = (
                db_api.reservation_get_all_by_lease_id(lease_id))

            try:
                invalid_ids = set([r['id'] for r in reservations]).difference(
                    [r['id'] for r in existing_reservations])
            except KeyError:
                raise exceptions.MissingParameter(param='reservation ID')

            if invalid_ids:
                raise common_ex.InvalidInput(
                    'Please enter valid reservation IDs. Invalid reservation '
                    'IDs are: %s' % ','.join([str(id) for id in invalid_ids]))

            try:
                [
                    self.plugins[r['resource_type']] for r
                    in (reservations + existing_reservations)]
            except KeyError:
                raise exceptions.CantUpdateParameter(param='resource_type')

            existing_allocs = self._existing_allocations(existing_reservations)

            if reservations:
                new_reservations = reservations
                new_allocs = self._allocation_candidates(values,
                                                         existing_reservations)
            else:
                # User is not updating reservation parameters, e.g., is only
                # adjusting lease start/end dates.
                new_reservations = existing_reservations
                new_allocs = existing_allocs

            try:
                self.enforcement.check_update(context.current(), lease, values,
                                              existing_allocs, new_allocs,
                                              existing_reservations,
                                              new_reservations)
            except common_ex.NotAuthorized as e:
                LOG.error("Enforcement checks failed. %s", str(e))
                raise common_ex.NotAuthorized(e)

            # TODO(frossigneux) rollback if an exception is raised
            for reservation in existing_reservations:
                v = {}
                v['start_date'] = values['start_date']
                v['end_date'] = values['end_date']
                try:
                    v.update([r for r in reservations
                              if r['id'] == reservation['id']].pop())
                except IndexError:
                    pass
                resource_type = v.get('resource_type',
                                      reservation['resource_type'])

                if resource_type != reservation['resource_type']:
                    raise exceptions.CantUpdateParameter(
                        param='resource_type')
                self.plugins[resource_type].update_reservation(
                    reservation['id'], v)

        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.BlazarException(
                '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.BlazarException(
                '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)

        try:
            del values['reservations']
        except KeyError:
            pass
        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
예제 #5
0
파일: service.py 프로젝트: stackhpc/blazar
    def create_lease(self, lease_values):
        """Create a lease with reservations.

        Return either the model of created lease or None if any error.
        """
        lease_values['status'] = status.lease.CREATING

        try:
            trust_id = lease_values.pop('trust_id')
        except KeyError:
            raise exceptions.MissingTrustId()

        self.validate_params(lease_values, ['name', 'start_date', 'end_date'])

        # Remove and keep event and reservation values
        events = lease_values.pop("events", [])
        reservations = lease_values.pop("reservations", [])
        for res in reservations:
            self.validate_params(res, ['resource_type'])

        # Create the lease without the reservations
        start_date, end_date, now = self._parse_lease_dates(
            lease_values['start_date'], lease_values['end_date'])

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

        if end_date <= start_date:
            raise common_ex.InvalidInput(
                'End date must be later than start date.')

        with trusts.create_ctx_from_trust(trust_id) as ctx:
            # NOTE(priteau): We should not get user_id from ctx, because we are
            # in the context of the trustee (blazar user).
            # lease_values['user_id'] is set in blazar/api/v1/service.py
            lease_values['project_id'] = ctx.project_id
            lease_values['start_date'] = start_date
            lease_values['end_date'] = end_date

            allocations = self._allocation_candidates(
                lease_values, reservations)
            try:
                self.enforcement.check_create(
                    context.current(), lease_values, reservations, allocations)
            except common_ex.NotAuthorized as e:
                LOG.error("Enforcement checks failed. %s", str(e))
                raise common_ex.NotAuthorized(e)

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

            before_end_date = lease_values.get('before_end_date', 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.BlazarException as e:
                    LOG.error("Invalid before_end_date param. %s", str(e))
                    raise e
            elif CONF.manager.minutes_before_end_lease > 0:
                delta = datetime.timedelta(
                    minutes=CONF.manager.minutes_before_end_lease)
                before_end_date = lease_values['end_date'] - delta

            if before_end_date:
                event = {'event_type': 'before_end_lease',
                         'status': status.event.UNDONE}
                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.BlazarDBDuplicateEntry:
                LOG.exception('Cannot create a lease - duplicated lease name')
                raise exceptions.LeaseNameAlreadyExists(
                    name=lease_values['name'])
            except db_ex.BlazarDBException:
                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']
                        self._create_reservation(reservation)
                except Exception:
                    LOG.exception("Failed to create reservation for a lease. "
                                  "Rollback the lease and associated "
                                  "reservations")
                    db_api.lease_destroy(lease_id)
                    raise

                try:
                    for event in events:
                        event['lease_id'] = lease['id']
                        db_api.event_create(event)
                except (exceptions.UnsupportedResourceType,
                        common_ex.BlazarException):
                    LOG.exception("Failed to create event for a lease. "
                                  "Rollback the lease and associated "
                                  "reservations")
                    db_api.lease_destroy(lease_id)
                    raise

                else:
                    db_api.lease_update(
                        lease_id,
                        {'status': status.lease.PENDING})
                    lease = db_api.lease_get(lease_id)
                    self._send_notification(lease, ctx, events=['create'])
                    return lease
예제 #6
0
파일: nova.py 프로젝트: zhenz/blazar
    def __init__(self, **kwargs):
        """Description

        BlazarNovaClient can be used in two ways: from context or kwargs.

        :param version: service client version which we will use
        :type version: str

        :param ctx: request context
        :type ctx: context object

        :param auth_token: keystone auth token
        :type auth_token: str

        :param endpoint_override: endpoint url which we will use
        :type endpoint_override: str

        :param username: username to use with nova client
        :type username: str

        :param password: password to use with nova client
        :type password: str

        :param user_domain_name: domain name of the user
        :type user_domain_name: str

        :param project_name: project name to use with nova client
        :type project_name: str

        :param project_domain_name: domain name of the project
        :type project_domain_name: str

        :param auth_url: keystone url to authenticate against
        :type auth_url: str
        """

        ctx = kwargs.pop('ctx', None)
        auth_token = kwargs.pop('auth_token', None)
        endpoint_override = kwargs.pop('endpoint_override', None)
        version = kwargs.pop('version', CONF.nova.nova_client_version)
        username = kwargs.pop('username', None)
        password = kwargs.pop('password', None)
        user_domain_name = kwargs.pop('user_domain_name', None)
        project_name = kwargs.pop('project_name', None)
        project_domain_name = kwargs.pop('project_domain_name', None)
        auth_url = kwargs.pop('auth_url', None)

        if ctx is None:
            try:
                ctx = context.current()
            except RuntimeError:
                pass
        if ctx is not None:
            auth_token = auth_token or ctx.auth_token
            endpoint_override = endpoint_override or \
                base.url_for(ctx.service_catalog,
                             CONF.nova.compute_service,
                             os_region_name=CONF.os_region_name)
            auth_url = base.url_for(ctx.service_catalog,
                                    CONF.identity_service,
                                    os_region_name=CONF.os_region_name)
            kwargs.setdefault('global_request_id', ctx.global_request_id)

        if auth_url is None:
            auth_url = "%s://%s:%s" % (CONF.os_auth_protocol,
                                       base.get_os_auth_host(CONF),
                                       CONF.os_auth_port)
            if CONF.os_auth_prefix:
                auth_url += "/%s" % CONF.os_auth_prefix

        if username:
            kwargs.setdefault('username', username)
            kwargs.setdefault('password', password)
            kwargs.setdefault('project_name', project_name)
            kwargs.setdefault('auth_url', auth_url)

            if "v2.0" not in auth_url:
                kwargs.setdefault('project_domain_name', project_domain_name)
                kwargs.setdefault('user_domain_name', user_domain_name)
        else:
            auth = token_endpoint.Token(endpoint_override, auth_token)
            sess = session.Session(auth=auth)
            kwargs.setdefault('session', sess)

        kwargs.setdefault('endpoint_override', endpoint_override)
        kwargs.setdefault('version', version)
        self.nova = nova_client.Client(**kwargs)

        self.nova.servers = ServerManager(self.nova)

        self.exceptions = nova_exception
    def test_on_end(self):
        allocations = {'virtual:instance': [get_fake_host('1')]}
        lease = get_fake_lease()
        ctx = context.current()

        self.enforcement.on_end(ctx, lease, allocations)
예제 #8
0
    def __init__(self, **kwargs):
        """Description

        Return Keystone client for defined in 'identity_service' conf.
        NOTE: We will use tenant_name until we start using keystone V3
        client for all our needs.

        :param version: service client version which we will use
        :type version: str

        :param username: username
        :type username: str

        :param password: password
        :type password: str

        :param tenant_name: tenant_name
        :type tenant_name: str

        :param auth_url: auth_url
        :type auth_url: str

        :param ctx: blazar context object
        :type ctx: dict

        :param auth_url: keystone auth url
        :type auth_url: string

        :param endpoint: keystone management (endpoint) url
        :type endpoint: string

        :param trust_id: keystone trust ID
        :type trust_id: string

        :param token: user token to use for authentication
        :type token: string
        """

        ctx = kwargs.pop('ctx', None)
        if ctx is None:
            try:
                ctx = context.current()
            except RuntimeError:
                pass

        kwargs.setdefault('version', cfg.CONF.keystone_client_version)
        if ctx is not None:
            kwargs.setdefault('username', ctx.user_name)
            kwargs.setdefault('tenant_name', ctx.project_name)
            kwargs.setdefault('global_request_id', ctx.global_request_id)
            if not kwargs.get('auth_url'):
                kwargs['auth_url'] = base.url_for(
                    ctx.service_catalog, CONF.identity_service,
                    os_region_name=CONF.os_region_name)
            if not kwargs.get('trust_id'):
                try:
                    kwargs.setdefault('endpoint', base.url_for(
                        ctx.service_catalog, CONF.identity_service,
                        endpoint_interface='admin',
                        os_region_name=CONF.os_region_name))
                except AttributeError:
                    raise manager_exceptions.NoManagementUrl()
            if not kwargs.get('password'):
                kwargs.setdefault('token', ctx.auth_token)

        # NOTE(dbelova): we need this checking to support current
        # keystoneclient: token can only be scoped now to either
        # a trust or project, not both.
        if kwargs.get('trust_id') and kwargs.get('tenant_name'):
            kwargs.pop('tenant_name')

        try:
            # NOTE(n.s.): we shall remove this try: except: clause when
            # https://review.openstack.org/#/c/66494/ will be merged
            self.keystone = keystone_client.Client(**kwargs)
            self.keystone.session.auth = self.keystone
            auth_url = self.complement_auth_url(kwargs.get('auth_url', None),
                                                kwargs.get('version', None))
            self.keystone.authenticate(auth_url=auth_url)
        except AttributeError:
            raise manager_exceptions.WrongClientVersion()

        self.exceptions = keystone_exception
예제 #9
0
    def _update_allocations(self, dates_before, dates_after, reservation_id,
                            reservation_status, fip_reservation, values):
        amount = int(values.get('amount', fip_reservation['amount']))
        fip_allocations = db_api.fip_allocation_get_all_by_values(
            reservation_id=reservation_id)
        allocs_to_remove = self._allocations_to_remove(dates_before,
                                                       dates_after,
                                                       fip_allocations, amount)

        if (allocs_to_remove
                and reservation_status == status.reservation.ACTIVE):
            raise manager_ex.CantUpdateFloatingIPReservation(
                msg="Cannot remove allocations from an active reservation")

        kept_fips = len(fip_allocations) - len(allocs_to_remove)
        fip_ids_to_add = []

        if kept_fips < amount:
            needed_fips = amount - kept_fips
            required_fips = values.get('required_floatingips',
                                       fip_reservation['required_floatingips'])
            fip_ids_to_add = self._matching_fips(fip_reservation['network_id'],
                                                 required_fips, needed_fips,
                                                 dates_after['start_date'],
                                                 dates_after['end_date'])

            if len(fip_ids_to_add) < needed_fips:
                raise manager_ex.NotEnoughFloatingIPAvailable()

        # Create new floating IPs if reservation is active
        created_fips = []
        if reservation_status == status.reservation.ACTIVE:
            ctx = context.current()
            fip_pool = neutron.FloatingIPPool(fip_reservation['network_id'])
            for fip_id in fip_ids_to_add:
                try:
                    fip = db_api.floatingip_get(fip_id)
                    LOG.debug(
                        'Creating floating IP {} for reservation {}'.format(
                            fip['floating_ip_address'], reservation_id))
                    fip_pool.create_reserved_floatingip(
                        fip['subnet_id'], fip['floating_ip_address'],
                        ctx.project_id, reservation_id)
                    created_fips.append(fip['floating_ip_address'])
                except Exception as e:
                    for fip_address in created_fips:
                        fip_pool.delete_reserved_floatingip(fip_address)
                    err_msg = 'Failed to create floating IP: {}'.format(str(e))
                    raise manager_ex.NeutronClientError(err_msg)

        for fip_id in fip_ids_to_add:
            LOG.debug('Adding floating IP {} to reservation {}'.format(
                fip_id, reservation_id))
            db_api.fip_allocation_create({
                'floatingip_id': fip_id,
                'reservation_id': reservation_id
            })

        for allocation in allocs_to_remove:
            LOG.debug('Removing floating IP {} from reservation {}'.format(
                allocation['floatingip_id'], reservation_id))
            db_api.fip_allocation_destroy(allocation['id'])
예제 #10
0
 def call(self, name, **kwargs):
     ctx = context.current()
     return self._client.call(ctx.to_dict(), name, **kwargs)
예제 #11
0
 def cast(self, name, **kwargs):
     ctx = context.current()
     self._client.cast(ctx.to_dict(), name, **kwargs)