def execute(self, service_settings): logger.debug('About to connect service settings "%s" to all available customers' % service_settings.name) if not service_settings.shared: raise ValueError('It is impossible to connect non-shared settings') service_model = SupportedServices.get_service_models()[service_settings.type]['service'] with transaction.atomic(): for customer in models.Customer.objects.all(): defaults = {'available_for_all': True} service, _ = service_model.objects.get_or_create( customer=customer, settings=service_settings, defaults=defaults) service_project_link_model = service.projects.through for project in service.customer.projects.all(): service_project_link_model.objects.get_or_create(project=project, service=service) logger.info('Successfully connected service settings "%s" to all available customers' % service_settings.name)
def get_queryset(self): queryset = models.DefaultPriceListItem.objects.all() service = self._find_service() if service: # Filter items by resource type resources = SupportedServices.get_related_models(service)['resources'] content_types = ContentType.objects.get_for_models(*resources).values() queryset = queryset.filter(resource_content_type__in=content_types) # Attach service-specific items price_list_items = models.PriceListItem.objects.filter(service=service) prefetch = Prefetch( 'pricelistitem_set', queryset=price_list_items, to_attr='service_item' ) queryset = queryset.prefetch_related(prefetch) return queryset
def _get_log_context(self, entity_name): context = super(ResourceMixin, self)._get_log_context(entity_name) # XXX: Add resource_full_name here, because event context does not support properties as fields context['resource_full_name'] = self.full_name # required for lookups in ElasticSearch by the client context['resource_type'] = SupportedServices.get_name_for_model(self) # XXX: a hack for IaaS / PaaS / SaaS tags # XXX: should be moved to itacloud assembly if self.tags.filter(name='IaaS').exists(): context['resource_delivery_model'] = 'IaaS' elif self.tags.filter(name='PaaS').exists(): context['resource_delivery_model'] = 'PaaS' elif self.tags.filter(name='SaaS').exists(): context['resource_delivery_model'] = 'SaaS' return context
def services(self, request, pk=None): settings = models.ServiceSettings.objects.get(id=pk) projects = {} spl_model = SupportedServices.get_related_models(settings)['service_project_link'] for spl in spl_model.objects.filter(service__settings=settings): projects.setdefault(spl.project.id, { 'name': six.text_type(spl.project), 'url': get_admin_url(spl.project), 'services': [], }) projects[spl.project.id]['services'].append({ 'name': six.text_type(spl.service), 'url': get_admin_url(spl.service), }) return render(request, 'structure/service_settings_entities.html', {'projects': projects.values()})
def get_resources_for_import(self): cur_droplets = models.Droplet.objects.all().values_list('backend_id', flat=True) statuses = ('active', 'off') droplets = self.get_all_droplets() return [ { 'id': droplet.id, 'name': droplet.name, 'created_at': droplet.created_at, 'cores': droplet.vcpus, 'ram': droplet.memory, 'disk': self.gb2mb(droplet.disk), 'flavor_name': droplet.size_slug, 'resource_type': SupportedServices.get_name_for_model(models.Droplet), } for droplet in droplets if str(droplet.id) not in cur_droplets and droplet.status in statuses ]
def connect_customer_to_shared_service_settings(sender, instance, created=False, **kwargs): if not created: return customer = instance for shared_settings in ServiceSettings.objects.filter(shared=True): try: service_model = SupportedServices.get_service_models()[ shared_settings.type]['service'] service_model.objects.create(customer=customer, settings=shared_settings, available_for_all=True) except KeyError: logger.warning("Unregistered service of type %s" % shared_settings.type)
def run(self): date = datetime.now() - timedelta(days=1) start_date = date.replace(hour=0, minute=0, second=0, microsecond=0) end_date = start_date + timedelta(days=1, microseconds=-1) # XXX: it's just a placeholder, it doesn't work properly now nor implemented anyhow # perhaps it should merely use price estimates.. models = SupportedServices.get_resource_models().values() for model in models: resources = model.objects.filter( service_project_link__service__settings__shared=True) for resource in resources: try: data = resource.get_cost(start_date, end_date) except NotImplementedError: continue else: resource.customer.debit_account(data['total_amount'])
def connect_shared_settings(service_settings): logger.debug( 'About to connect service settings "%s" to all available customers' % service_settings.name) if not service_settings.shared: raise ValueError('It is impossible to connect non-shared settings') service_model = SupportedServices.get_service_models()[ service_settings.type]['service'] with transaction.atomic(): for customer in structure_models.Customer.objects.all(): defaults = {'available_for_all': True} try: service, _ = service_model.objects.get_or_create( customer=customer, settings=service_settings, defaults=defaults) except QuotaValidationError: logger.warning( 'Unable to connect shared service ' 'settings to customer because quota is exceeded. ' 'Service settings ID: %s, customer ID: %s', service_settings.id, customer.id, ) continue service_project_link_model = service.projects.through for project in service.customer.projects.all(): try: service_project_link_model.objects.get_or_create( project=project, service=service) except QuotaValidationError: logger.warning( 'Unable to connect shared service to project because ' 'quota is exceeded. Service ID: %s, project ID: %s', service.id, project.id, ) continue
def _create_service(self, service_type, validated_data): """ Marketplace offering model does not accept service_attributes field as is, therefore we should remove it from validated_data and create service settings object. Then we need to specify created object and offering's scope. """ name = validated_data['name'] service_attributes = validated_data.pop('service_attributes', {}) if not service_attributes: raise ValidationError({ 'service_attributes': _('This field is required.') }) payload = dict( name=name, # It is expected that customer URL is passed to the service settings serializer customer=self.initial_data['customer'], type=service_type, **service_attributes ) serializer_class = SupportedServices.get_service_serializer_for_key(service_type) serializer = serializer_class(data=payload, context=self.context) serializer.is_valid(raise_exception=True) service = serializer.save() # Usually we don't allow users to create new shared service settings via REST API. # That's shared flag is marked as read-only in service settings serializer. # But shared offering should be created with shared service settings. # That's why we set it to shared only after service settings object is created. if validated_data.get('shared'): service.settings.shared = True service.settings.save() # Usually connect shared settings task is called when service is created. # But as we set shared flag after serializer has been executed, # we need to connect shared settings manually. connect_shared_settings(service.settings) validated_data['scope'] = service.settings return validated_data
def filter_by_logged_object(self): return { 'resource_uuid': self.uuid.hex, 'resource_type': SupportedServices.get_name_for_model(self) }
def test_get_service_serializer(self): self.assertEqual(ServiceSerializer, SupportedServices.get_service_serializer(TestService))
def full_name(self): return '%s %s' % (SupportedServices.get_name_for_model(self).replace('.', ' '), self.name)
def ready(self): from waldur_core.structure import SupportedServices from .backend import AWSBackend SupportedServices.register_backend(AWSBackend)
def test_model_key(self): self.assertEqual(TestConfig.service_name, SupportedServices.get_model_key(TestNewInstance))
def _get_log_context(self, entity_name): context = super(Service, self)._get_log_context(entity_name) context['service_type'] = SupportedServices.get_name_for_model(self) return context
def get_type_display(self): return SupportedServices.get_name_for_type(self.type)
def get_resource_type(self, obj): if isinstance(obj.resource, structure_models.ResourceMixin): return SupportedServices.get_name_for_model(obj.resource_content_type.model_class())
def __init__(self, *args, **kwargs): super(ServiceSettingsAdminForm, self).__init__(*args, **kwargs) self.fields['type'] = ChoiceField( choices=SupportedServices.get_choices(), widget=RadioSelect)
def lookups(self, request, model_admin): return SupportedServices.get_choices()
def ready(self): from waldur_core.quotas.fields import QuotaField, CounterQuotaField from waldur_core.structure import SupportedServices from waldur_core.structure import models as structure_models from waldur_core.structure import signals as structure_signals from waldur_freeipa import models as freeipa_models from .backend import SlurmBackend from . import handlers, models, utils SupportedServices.register_backend(SlurmBackend) signals.post_save.connect( handlers.process_user_creation, sender=freeipa_models.Profile, dispatch_uid='waldur_slurm.handlers.process_user_creation', ) signals.pre_delete.connect( handlers.process_user_deletion, sender=freeipa_models.Profile, dispatch_uid='waldur_slurm.handlers.process_user_deletion', ) structure_models_with_roles = (structure_models.Customer, structure_models.Project) for model in structure_models_with_roles: structure_signals.structure_role_granted.connect( handlers.process_role_granted, sender=model, dispatch_uid='waldur_slurm.handlers.process_role_granted.%s' % model.__class__, ) structure_signals.structure_role_revoked.connect( handlers.process_role_revoked, sender=model, dispatch_uid='waldur_slurm.handlers.process_role_revoked.%s' % model.__class__, ) for quota in utils.QUOTA_NAMES: structure_models.Customer.add_quota_field( name=quota, quota_field=QuotaField(is_backend=True)) structure_models.Project.add_quota_field( name=quota, quota_field=QuotaField(is_backend=True)) structure_models.Project.add_quota_field( name='nc_allocation_count', quota_field=CounterQuotaField( target_models=lambda: [models.Allocation], path_to_scope='service_project_link.project', )) structure_models.Customer.add_quota_field( name='nc_allocation_count', quota_field=CounterQuotaField( target_models=lambda: [models.Allocation], path_to_scope='service_project_link.project.customer', )) signals.post_save.connect( handlers.update_quotas_on_allocation_usage_update, sender=models.Allocation, dispatch_uid= 'waldur_slurm.handlers.update_quotas_on_allocation_usage_update', )
def get_scope_type(cls): return SupportedServices.get_name_for_model(cls)
def get_marketplace_offering_uuid(serializer, scope): try: return models.Resource.objects.get(scope=scope).offering.uuid except ObjectDoesNotExist: return def add_marketplace_offering(sender, fields, **kwargs): fields['marketplace_offering_uuid'] = serializers.SerializerMethodField() setattr(sender, 'get_marketplace_offering_uuid', get_marketplace_offering_uuid) core_signals.pre_serializer_fields.connect( sender=structure_serializers.CustomerSerializer, receiver=add_service_provider, ) core_signals.pre_serializer_fields.connect( sender=support_serializers.OfferingSerializer, receiver=add_marketplace_offering, ) for resource_serializer in SupportedServices.get_resource_serializers(): core_signals.pre_serializer_fields.connect( sender=resource_serializer, receiver=add_marketplace_offering, )
def validate_service_type(service_type): from django.core.exceptions import ValidationError if not SupportedServices.has_service_type(service_type): raise ValidationError(_('Invalid service type.'))
def get_spl_model(self): """ Get service project link model used by resource model using service registry. """ return SupportedServices.get_related_models( self.get_resource_model())['service_project_link']
def get_backend(self, **kwargs): return SupportedServices.get_service_backend(self.type)(self, **kwargs)
def ready(self): SupportedServices.register_backend(TestBackend) SupportedServices.register_service(self.get_model('TestService'))
def get_services(self): service_model = SupportedServices.get_service_models()[self.type]['service'] return service_model.objects.filter(settings=self)
def ready(self): from waldur_core.core import signals as core_signals from waldur_core.quotas import signals as quota_signals from waldur_core.structure import SupportedServices from . import ( handlers, models, utils, signals as marketplace_signals, processors, ) from .plugins import manager signals.post_save.connect( handlers.create_screenshot_thumbnail, sender=models.Screenshot, dispatch_uid= 'waldur_mastermind.marketplace.create_screenshot_thumbnail', ) signals.post_save.connect( handlers.log_order_events, sender=models.Order, dispatch_uid='waldur_mastermind.marketplace.log_order_events', ) signals.post_save.connect( handlers.log_order_item_events, sender=models.OrderItem, dispatch_uid='waldur_mastermind.marketplace.log_order_item_events', ) signals.post_save.connect( handlers.log_resource_events, sender=models.Resource, dispatch_uid='waldur_mastermind.marketplace.log_resource_events', ) signals.post_save.connect( handlers.reject_order, sender=models.Order, dispatch_uid='waldur_mastermind.marketplace.reject_order', ) signals.post_save.connect( handlers.complete_order_when_all_items_are_done, sender=models.OrderItem, dispatch_uid= 'waldur_mastermind.marketplace.complete_order_when_all_items_are_done', ) signals.post_save.connect( handlers.update_category_quota_when_offering_is_created, sender=models.Offering, dispatch_uid= 'waldur_mastermind.marketplace.update_category_quota_when_offering_is_created', ) signals.post_delete.connect( handlers.update_category_quota_when_offering_is_deleted, sender=models.Offering, dispatch_uid= 'waldur_mastermind.marketplace.update_category_quota_when_offering_is_deleted', ) quota_signals.recalculate_quotas.connect( handlers.update_category_offerings_count, dispatch_uid= 'waldur_mastermind.marketplace.update_category_offerings_count', ) signals.post_save.connect( handlers.update_aggregate_resources_count_when_resource_is_updated, sender=models.Resource, dispatch_uid='waldur_mastermind.marketplace.' 'update_aggregate_resources_count_when_resource_is_updated', ) quota_signals.recalculate_quotas.connect( handlers.update_aggregate_resources_count, dispatch_uid= 'waldur_mastermind.marketplace.update_aggregate_resources_count', ) signals.post_save.connect( handlers.close_resource_plan_period_when_resource_is_terminated, sender=models.Resource, dispatch_uid='waldur_mastermind.marketplace.' 'close_resource_plan_period_when_resource_is_terminated', ) marketplace_signals.limit_update_succeeded.connect( handlers.limit_update_succeeded, sender=models.Resource, dispatch_uid='waldur_mastermind.marketplace.limit_update_succeeded', ) marketplace_signals.limit_update_failed.connect( handlers.limit_update_failed, sender=models.Resource, dispatch_uid='waldur_mastermind.marketplace.limit_update_failed', ) for resource_serializer in SupportedServices.get_resource_serializers( ): core_signals.pre_serializer_fields.connect( sender=resource_serializer, receiver=utils.add_marketplace_offering, ) signals.post_save.connect( handlers.add_component_usage, sender=models.ComponentUsage, dispatch_uid='waldur_mastermind.marketplace.add_component_usage', ) manager.register( offering_type='Marketplace.Basic', create_resource_processor=processors.BasicCreateResourceProcessor, update_resource_processor=processors.BasicUpdateResourceProcessor, delete_resource_processor=processors.BasicDeleteResourceProcessor, )
def filter(self, qs, value): value = SupportedServices.get_filter_mapping().get(value) return super(ServiceTypeFilter, self).filter(qs, value)
def test_get_service_resources(self): self.assertEqual([TestNewInstance], SupportedServices.get_service_resources(TestService))