def update(self, instance, validated_data): """Update a Provider instance from validated data.""" provider_type = validated_data['type'] interface = ProviderAccessor(provider_type) authentication = validated_data.pop('authentication') credentials = authentication.get('credentials') provider_resource_name = credentials.get('provider_resource_name') billing_source = validated_data.pop('billing_source') data_source = billing_source.get('data_source') bucket = billing_source.get('bucket') if credentials and data_source and provider_type not in ['AWS', 'OCP']: interface.cost_usage_source_ready(credentials, data_source) else: interface.cost_usage_source_ready(provider_resource_name, bucket) bill, __ = ProviderBillingSource.objects.get_or_create(**billing_source) auth, __ = ProviderAuthentication.objects.get_or_create(**authentication) for key in validated_data.keys(): setattr(instance, key, validated_data[key]) instance.authentication = auth instance.billing_source = bill try: instance.save() except IntegrityError: error = {'Error': 'A Provider already exists with that Authentication and Billing Source'} raise serializers.ValidationError(error) return instance
def update(self, instance, validated_data): """Update a Provider instance from validated data.""" _, customer = self.get_request_info() provider_type = validated_data["type"].lower() provider_type = Provider.PROVIDER_CASE_MAPPING.get(provider_type) validated_data["type"] = provider_type interface = ProviderAccessor(provider_type) authentication = validated_data.pop("authentication") credentials = authentication.get("credentials") billing_source = validated_data.pop("billing_source") data_source = billing_source.get("data_source") # updating `paused` must happen regardless of Provider availabilty instance.paused = validated_data.pop("paused", instance.paused) try: if self._is_demo_account(provider_type, credentials): LOG.info( "Customer account is a DEMO account. Skipping cost_usage_source_ready check." ) else: interface.cost_usage_source_ready(credentials, data_source) except serializers.ValidationError as validation_error: instance.active = False instance.save() raise validation_error with transaction.atomic(): bill, __ = ProviderBillingSource.objects.get_or_create( **billing_source) auth, __ = ProviderAuthentication.objects.get_or_create( **authentication) if instance.billing_source != bill or instance.authentication != auth: dup_queryset = (Provider.objects.filter( authentication=auth).filter(billing_source=bill).filter( customer=customer)) if dup_queryset.count() != 0: conflict_provder = dup_queryset.first() message = ( f"Cost management does not allow duplicate accounts. " f"{conflict_provder.name} already exists. Edit source settings to configure a new source." ) LOG.warn(message) raise serializers.ValidationError( error_obj(ProviderErrors.DUPLICATE_AUTH, message)) for key in validated_data.keys(): setattr(instance, key, validated_data[key]) instance.authentication = auth instance.billing_source = bill instance.active = True instance.save() customer.date_updated = DateHelper().now_utc customer.save() return instance
def create(self, validated_data): """Create a provider from validated data.""" user, customer = self.get_request_info() if "billing_source" in validated_data: billing_source = validated_data.pop("billing_source") data_source = billing_source.get("data_source", {}) bucket = data_source.get("bucket") else: # Because of a unique together constraint, this is done # to allow for this field to be non-required for OCP # but will still have a blank no-op entry in the DB billing_source = {"bucket": "", "data_source": {}} data_source = None authentication = validated_data.pop("authentication") credentials = authentication.get("credentials") provider_resource_name = credentials.get("provider_resource_name") provider_type = validated_data["type"] provider_type = Provider.PROVIDER_CASE_MAPPING.get(provider_type) validated_data["type"] = provider_type interface = ProviderAccessor(provider_type) if customer.account_id not in settings.DEMO_ACCOUNTS: if credentials and data_source and provider_type not in [ Provider.PROVIDER_AWS, Provider.PROVIDER_OCP ]: interface.cost_usage_source_ready(credentials, data_source) else: interface.cost_usage_source_ready(provider_resource_name, bucket) bill, __ = ProviderBillingSource.objects.get_or_create( **billing_source) auth, __ = ProviderAuthentication.objects.get_or_create( **authentication) # We can re-use a billing source or a auth, but not the same combination. dup_queryset = (Provider.objects.filter(authentication=auth).filter( billing_source=bill).filter(customer=customer)) if dup_queryset.count() != 0: conflict_provider = dup_queryset.first() message = ( f"Cost management does not allow duplicate accounts. " f"{conflict_provider.name} already exists. Edit source settings to configure a new source." ) LOG.warn(message) raise serializers.ValidationError( error_obj(ProviderErrors.DUPLICATE_AUTH, message)) provider = Provider.objects.create(**validated_data) provider.customer = customer provider.created_by = user provider.authentication = auth provider.billing_source = bill provider.active = True provider.save() return provider
def create(self, validated_data): """Create a provider from validated data.""" user = None customer = None request = self.context.get('request') if request and hasattr(request, 'user'): user = request.user if user.customer: customer = user.customer else: key = 'customer' message = 'Customer for requesting user could not be found.' raise serializers.ValidationError(error_obj(key, message)) else: key = 'created_by' message = 'Requesting user could not be found.' raise serializers.ValidationError(error_obj(key, message)) if 'billing_source' in validated_data: billing_source = validated_data.pop('billing_source') data_source = billing_source.get('data_source', {}) bucket = data_source.get('bucket') else: # Because of a unique together constraint, this is done # to allow for this field to be non-required for OCP # but will still have a blank no-op entry in the DB billing_source = {'bucket': '', 'data_source': {}} data_source = None authentication = validated_data.pop('authentication') credentials = authentication.get('credentials') provider_resource_name = credentials.get('provider_resource_name') provider_type = validated_data['type'] interface = ProviderAccessor(provider_type) if credentials and data_source and provider_type not in ['AWS', 'OCP']: interface.cost_usage_source_ready(credentials, data_source) else: interface.cost_usage_source_ready(provider_resource_name, bucket) bill, __ = ProviderBillingSource.objects.get_or_create(**billing_source) auth, __ = ProviderAuthentication.objects.get_or_create(**authentication) # We can re-use a billing source or a auth, but not the same combination. unique_count = Provider.objects.filter(authentication=auth)\ .filter(billing_source=bill).count() if unique_count != 0: error = {'Error': 'A Provider already exists with that Authentication and Billing Source'} raise serializers.ValidationError(error) provider = Provider.objects.create(**validated_data) provider.customer = customer provider.created_by = user provider.authentication = auth provider.billing_source = bill provider.active = True provider.save() return provider
def update(self, instance, validated_data): """Update a Provider instance from validated data.""" _, customer = self.get_request_info() provider_type = validated_data["type"].lower() provider_type = Provider.PROVIDER_CASE_MAPPING.get(provider_type) validated_data["type"] = provider_type interface = ProviderAccessor(provider_type) authentication = validated_data.pop("authentication") credentials = authentication.get("credentials") provider_resource_name = credentials.get("provider_resource_name") billing_source = validated_data.pop("billing_source") data_source = billing_source.get("data_source") bucket = billing_source.get("bucket") try: if customer.account_id not in settings.DEMO_ACCOUNTS: if credentials and data_source and provider_type not in [ Provider.PROVIDER_AWS, Provider.PROVIDER_OCP ]: interface.cost_usage_source_ready(credentials, data_source) else: interface.cost_usage_source_ready(provider_resource_name, bucket) except serializers.ValidationError as validation_error: instance.active = False instance.save() raise validation_error with transaction.atomic(): bill, __ = ProviderBillingSource.objects.get_or_create( **billing_source) auth, __ = ProviderAuthentication.objects.get_or_create( **authentication) dup_queryset = (Provider.objects.filter( authentication=auth).filter(billing_source=bill).filter( customer=customer)) if dup_queryset.count() != 0: conflict_provder = dup_queryset.first() message = ( f"Cost management does not allow duplicate accounts. " f"{conflict_provder.name} already exists. Edit source settings to configure a new source." ) LOG.warn(message) for key in validated_data.keys(): setattr(instance, key, validated_data[key]) instance.authentication = auth instance.billing_source = bill instance.active = True try: instance.save() except IntegrityError: raise serializers.ValidationError( error_obj(ProviderErrors.DUPLICATE_AUTH, message)) return instance
def update(self, instance, validated_data): """Update a Provider instance from validated data.""" _, _, customer = self.get_request_info() provider_type = validated_data["type"].lower() provider_type = Provider.PROVIDER_CASE_MAPPING.get(provider_type) validated_data["type"] = provider_type if instance.type != provider_type: error = { "Error": "The Provider Type cannot be changed with a PUT request." } raise serializers.ValidationError(error) interface = ProviderAccessor(provider_type) authentication = validated_data.pop("authentication") credentials = authentication.get("credentials") provider_resource_name = credentials.get("provider_resource_name") billing_source = validated_data.pop("billing_source") data_source = billing_source.get("data_source") bucket = billing_source.get("bucket") try: if customer.account_id not in settings.DEMO_ACCOUNTS: if credentials and data_source and provider_type not in [ Provider.PROVIDER_AWS, Provider.PROVIDER_OCP ]: interface.cost_usage_source_ready(credentials, data_source) else: interface.cost_usage_source_ready(provider_resource_name, bucket) except serializers.ValidationError as validation_error: instance.active = False instance.save() raise validation_error with transaction.atomic(): bill, __ = ProviderBillingSource.objects.get_or_create( **billing_source) auth, __ = ProviderAuthentication.objects.get_or_create( **authentication) for key in validated_data.keys(): setattr(instance, key, validated_data[key]) instance.authentication = auth instance.billing_source = bill instance.active = True try: instance.save() except IntegrityError: error = { "Error": "A Provider already exists with that Authentication and Billing Source" } raise serializers.ValidationError(error) return instance
def create(self, validated_data): """Create a provider from validated data.""" _, user, customer = self.get_request_info() if "billing_source" in validated_data: billing_source = validated_data.pop("billing_source") data_source = billing_source.get("data_source", {}) bucket = data_source.get("bucket") else: # Because of a unique together constraint, this is done # to allow for this field to be non-required for OCP # but will still have a blank no-op entry in the DB billing_source = {"bucket": "", "data_source": {}} data_source = None authentication = validated_data.pop("authentication") credentials = authentication.get("credentials") provider_resource_name = credentials.get("provider_resource_name") provider_type = validated_data["type"] provider_type = Provider.PROVIDER_CASE_MAPPING.get(provider_type) validated_data["type"] = provider_type interface = ProviderAccessor(provider_type) if customer.account_id not in settings.DEMO_ACCOUNTS: if credentials and data_source and provider_type not in [ Provider.PROVIDER_AWS, Provider.PROVIDER_OCP ]: interface.cost_usage_source_ready(credentials, data_source) else: interface.cost_usage_source_ready(provider_resource_name, bucket) bill, __ = ProviderBillingSource.objects.get_or_create( **billing_source) auth, __ = ProviderAuthentication.objects.get_or_create( **authentication) # We can re-use a billing source or a auth, but not the same combination. unique_count = (Provider.objects.filter(authentication=auth).filter( billing_source=bill).filter(customer=customer).count()) if unique_count != 0: error = { "Error": "A Provider already exists with that Authentication and Billing Source" } raise serializers.ValidationError(error) provider = Provider.objects.create(**validated_data) provider.customer = customer provider.created_by = user provider.authentication = auth provider.billing_source = bill provider.active = True provider.save() return provider
def determine_status(self, provider, source_authentication, source_billing_source): """Check cloud configuration status.""" interface = ProviderAccessor(provider) error_obj = None try: interface.cost_usage_source_ready(source_authentication, source_billing_source) except ValidationError as validation_error: error_obj = validation_error return error_obj
def determine_status(self, provider_type, source_authentication, source_billing_source): """Check cloud configuration status.""" interface = ProviderAccessor(provider_type) error_obj = None try: if self.source.account_id not in settings.DEMO_ACCOUNTS: interface.cost_usage_source_ready(source_authentication, source_billing_source) self._set_provider_active_status(True) except ValidationError as validation_error: self._set_provider_active_status(False) error_obj = validation_error self.source.refresh_from_db() return error_obj
def create(self, validated_data): """Create a provider from validated data.""" user, customer = self.get_request_info() provider_type = validated_data["type"].lower() provider_type = Provider.PROVIDER_CASE_MAPPING.get(provider_type) validated_data["type"] = provider_type interface = ProviderAccessor(provider_type) authentication = validated_data.pop("authentication") credentials = authentication.get("credentials") billing_source = validated_data.pop("billing_source") data_source = billing_source.get("data_source") if self._is_demo_account(provider_type, credentials): LOG.info( "Customer account is a DEMO account. Skipping cost_usage_source_ready check." ) else: interface.cost_usage_source_ready(credentials, data_source) bill, __ = ProviderBillingSource.objects.get_or_create( **billing_source) auth, __ = ProviderAuthentication.objects.get_or_create( **authentication) # We can re-use a billing source or a auth, but not the same combination. dup_queryset = (Provider.objects.filter(authentication=auth).filter( billing_source=bill).filter(customer=customer)) if dup_queryset.count() != 0: conflict_provider = dup_queryset.first() message = ( f"Cost management does not allow duplicate accounts. " f"{conflict_provider.name} already exists. Edit source settings to configure a new source." ) LOG.warn(message) raise serializers.ValidationError( error_obj(ProviderErrors.DUPLICATE_AUTH, message)) provider = Provider.objects.create(**validated_data) provider.customer = customer provider.created_by = user provider.authentication = auth provider.billing_source = bill provider.active = True provider.save() customer.date_updated = DateHelper().now_utc customer.save() return provider
def test_invalid_provider_funcs(self): """Verify that an invalid service is created and raises errors.""" provider_name = "BAD" interface = ProviderAccessor(provider_name) self.assertIsNone(interface.service) with self.assertRaises(ValidationError): interface.cost_usage_source_ready({}, {}) with self.assertRaises(ValidationError): interface.service_name() with self.assertRaises(ValidationError): interface.infrastructure_type({}, {}) with self.assertRaises(ValidationError): interface.infrastructure_key_list({}, {})
def test_usage_source_ready(self): """Get status of cost usage source.""" provider = Provider.PROVIDER_AWS interface = ProviderAccessor(provider) credential = "arn:aws:s3:::my_s3_bucket" source_name = "my_s3_bucket" source_ready = False with patch.object(AWSProvider, "cost_usage_source_is_reachable", return_value=True): source_ready = interface.cost_usage_source_ready(credential, source_name) self.assertTrue(source_ready)
def create(self, validated_data): """Create a provider from validated data.""" authentication = validated_data.pop('authentication') billing_source = validated_data.pop('billing_source') user = None customer = None request = self.context.get('request') if request and hasattr(request, 'user'): user = User.objects.get(pk=request.user.id) if user.groups.count() == 1: group = user.groups.first() customer = Customer.objects.get(pk=group.id) else: key = 'customer' message = 'Group for requesting user could not be found.' raise serializers.ValidationError(error_obj(key, message)) else: key = 'created_by' message = 'Requesting user could not be found.' raise serializers.ValidationError(error_obj(key, message)) provider_resource_name = authentication.get('provider_resource_name') bucket = billing_source.get('bucket') provider_type = validated_data['type'] interface = ProviderAccessor(provider_type) interface.cost_usage_source_ready(provider_resource_name, bucket) auth = ProviderAuthentication.objects.create(**authentication) bill = ProviderBillingSource.objects.create(**billing_source) auth.save() bill.save() provider = Provider.objects.create(**validated_data) provider.customer = customer provider.created_by = user provider.authentication = auth provider.billing_source = bill provider.save() return provider