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)
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)
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)
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
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
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)
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
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'])
def call(self, name, **kwargs): ctx = context.current() return self._client.call(ctx.to_dict(), name, **kwargs)
def cast(self, name, **kwargs): ctx = context.current() self._client.cast(ctx.to_dict(), name, **kwargs)