Пример #1
0
    def test_user_preference_locale(self):
        """Test that valid locales are saved."""
        user = None
        serializer = UserSerializer(data=self.user_data,
                                    context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()

        kwargs = {'context': {'user': user}}
        data = {'name': 'locale',
                'description': self.fake.text(),
                'preference': {'locale': 'tg_TJ.KOI8-C'}}

        pref = list(UserPreference.objects.filter(user=user, name='locale')).pop()
        self.assertIsNotNone(pref)
        self.assertIsInstance(pref, UserPreference)

        serializer = UserPreferenceSerializer(pref, data=data, **kwargs)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

        self.assertEqual(pref.name, data.get('name'))
        self.assertEqual(pref.description, data.get('description'))
        self.assertEqual(pref.preference, data.get('preference'))
Пример #2
0
    def setUp(self):
        """Set up the tests."""
        super().setUp()
        request = self.request_context['request']
        serializer = UserSerializer(data=self.user_data,
                                    context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()
            request.user = user

        provider_data = {
            'name': 'test_provider',
            'type': Provider.PROVIDER_OCP,
            'authentication': {
                'provider_resource_name': self.fake.word()
            }
        }
        serializer = ProviderSerializer(data=provider_data,
                                        context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            self.provider = serializer.save()
Пример #3
0
    def test_user_preference_currency(self):
        """Test that valid currency codes are saved."""
        user = None
        serializer = UserSerializer(data=self.user_data)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()

        kwargs = {'context': {'user': user}}
        data = {'name': 'currency',
                'description': self.fake.text(),
                'preference': {'currency': random.choice(_currency_symbols())}}

        pref = list(UserPreference.objects.filter(user=user, name='currency')).pop()
        self.assertIsNotNone(pref)
        self.assertIsInstance(pref, UserPreference)

        serializer = UserPreferenceSerializer(pref, data=data, **kwargs)
        if serializer.is_valid(raise_exception=True):
            pref = serializer.save()

        self.assertEqual(pref.name, data.get('name'))
        self.assertEqual(pref.description, data.get('description'))
        self.assertEqual(pref.preference, data.get('preference'))
Пример #4
0
    def test_user_preference_timezone(self):
        """Test that valid timezones are saved."""
        user = None
        serializer = UserSerializer(data=self.user_data)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()

        kwargs = {'context': {'user': user}}
        data = {'name': 'timezone',
                'description': self.fake.text(),
                'preference': {'timezone': 'Antarctica/Troll'}}

        pref = list(UserPreference.objects.filter(user=user, name='timezone')).pop()
        self.assertIsNotNone(pref)
        self.assertIsInstance(pref, UserPreference)

        serializer = UserPreferenceSerializer(pref, data=data, **kwargs)
        if serializer.is_valid(raise_exception=True):
            pref = serializer.save()

        self.assertEqual(pref.name, data.get('name'))
        self.assertEqual(pref.description, data.get('description'))
        self.assertEqual(pref.preference, data.get('preference'))
Пример #5
0
class ProviderSerializer(serializers.ModelSerializer):
    """Serializer for the Provider  model."""

    uuid = serializers.UUIDField(read_only=True)
    name = serializers.CharField(max_length=256,
                                 required=True,
                                 allow_null=False,
                                 allow_blank=False)
    type = serializers.ChoiceField(choices=Provider.PROVIDER_CHOICES)
    authentication = ProviderAuthenticationSerializer()
    billing_source = ProviderBillingSourceSerializer()
    customer = CustomerSerializer(read_only=True)
    created_by = UserSerializer(read_only=True)

    class Meta:
        """Metadata for the serializer."""

        model = Provider
        fields = ('uuid', 'name', 'type', 'authentication', 'billing_source',
                  'customer', 'created_by')

    @transaction.atomic
    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
Пример #6
0
class ProviderSerializer(serializers.ModelSerializer):
    """Serializer for the Provider model."""

    uuid = serializers.UUIDField(allow_null=True, required=False)
    name = serializers.CharField(max_length=256,
                                 required=True,
                                 allow_null=False,
                                 allow_blank=False)
    type = serializers.ChoiceField(choices=LCASE_PROVIDER_CHOICE_LIST)
    created_timestamp = serializers.DateTimeField(read_only=True)
    customer = CustomerSerializer(read_only=True)
    created_by = UserSerializer(read_only=True)
    active = serializers.BooleanField(read_only=True)

    # pylint: disable=too-few-public-methods
    class Meta:
        """Metadata for the serializer."""

        model = Provider
        fields = (
            "uuid",
            "name",
            "type",
            "authentication",
            "billing_source",
            "customer",
            "created_by",
            "created_timestamp",
            "active",
        )

    def __init__(self, instance=None, data=empty, **kwargs):
        """Initialize the Provider Serializer.

        Here we ensure we use the appropriate serializer to validate the
        authentication and billing_source parameters.
        """
        super().__init__(instance, data, **kwargs)

        provider_type = None
        if data and data != empty:
            provider_type = data.get("type")

        if provider_type and provider_type.lower(
        ) not in LCASE_PROVIDER_CHOICE_LIST:
            key = "type"
            message = f"{provider_type} is not a valid source type."
            raise serializers.ValidationError(error_obj(key, message))

        if provider_type:
            provider_type = provider_type.lower()
            self.fields["authentication"] = AUTHENTICATION_SERIALIZERS.get(
                Provider.PROVIDER_CASE_MAPPING.get(provider_type))()
            self.fields["billing_source"] = BILLING_SOURCE_SERIALIZERS.get(
                Provider.PROVIDER_CASE_MAPPING.get(provider_type))(default={
                    "bucket": "",
                    "data_source": {
                        "bucket": ""
                    }
                })
        else:
            self.fields["authentication"] = ProviderAuthenticationSerializer()
            self.fields["billing_source"] = ProviderBillingSourceSerializer()

    def get_request_info(self):
        """Obtain request information like user and customer context."""
        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))
        return request, user, customer

    @transaction.atomic
    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 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
Пример #7
0
    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        serializer = UserSerializer(data=self.user_data,
                                    context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

        self.report = {
            'group_by': {
                'account': ['*']
            },
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month',
                'resource_scope': []
            },
            'data': [{
                'date':
                '2018-07',
                'accounts': [{
                    'account':
                    '4418636104713',
                    'values': [{
                        'date': '2018-07',
                        'units': 'GB-Mo',
                        'account': '4418636104713',
                        'total': 1826.74238146924
                    }]
                }, {
                    'account':
                    '8577742690384',
                    'values': [{
                        'date': '2018-07',
                        'units': 'GB-Mo',
                        'account': '8577742690384',
                        'total': 1137.74036198065
                    }]
                }, {
                    'account':
                    '3474227945050',
                    'values': [{
                        'date': '2018-07',
                        'units': 'GB-Mo',
                        'account': '3474227945050',
                        'total': 1045.80659412797
                    }]
                }, {
                    'account':
                    '7249815104968',
                    'values': [{
                        'date': '2018-07',
                        'units': 'GB-Mo',
                        'account': '7249815104968',
                        'total': 807.326470618818
                    }]
                }, {
                    'account':
                    '9420673783214',
                    'values': [{
                        'date': '2018-07',
                        'units': 'GB-Mo',
                        'account': '9420673783214',
                        'total': 658.306642830709
                    }]
                }]
            }],
            'total': {
                'value': 5475.922451027388,
                'units': 'GB-Mo'
            }
        }
Пример #8
0
    def setUp(self):
        """Set up the rate view tests."""
        super().setUp()
        request = self.request_context['request']
        serializer = UserSerializer(data=self.user_data,
                                    context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()
            request.user = user

        provider_data = {
            'name': 'test_provider',
            'type': Provider.PROVIDER_OCP,
            'authentication': {
                'provider_resource_name': self.fake.word()
            }
        }
        serializer = ProviderSerializer(data=provider_data,
                                        context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            self.provider = serializer.save()

        self.fake_data = {
            'provider_uuid':
            self.provider.uuid,
            'metric':
            Rate.METRIC_MEM_GB_USAGE_HOUR,
            'tiered_rate': [{
                'value': round(Decimal(random.random()), 6),
                'unit': 'USD',
                'usage_start': None,
                'usage_end': None
            }]
        }
        with tenant_context(self.tenant):
            serializer = RateSerializer(data=self.fake_data,
                                        context=self.request_context)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
Пример #9
0
    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        serializer = UserSerializer(data=self.user_data, context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

        self.report = {
            'group_by': {
                'subscription_guid': ['*']
            },
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month',
                'resource_scope': []
            },
            'data': [
                {
                    'date': '2018-07',
                    'subscription_guids': [
                        {
                            'subscription_guid': '00000000-0000-0000-0000-000000000000',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'subscription_guid': '00000000-0000-0000-0000-000000000000',
                                    'total': 1826.74238146924
                                }
                            ]
                        },
                        {
                            'subscription_guid': '11111111-1111-1111-1111-111111111111',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'subscription_guid': '11111111-1111-1111-1111-111111111111',
                                    'total': 1137.74036198065
                                }
                            ]
                        },
                        {
                            'subscription_guid': '22222222-2222-2222-2222-222222222222',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'subscription_guid': '22222222-2222-2222-2222-222222222222',
                                    'total': 1045.80659412797
                                }
                            ]
                        },
                        {
                            'subscription_guid': '33333333-3333-3333-3333-333333333333',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'subscription_guid': '33333333-3333-3333-3333-333333333333',
                                    'total': 807.326470618818
                                }
                            ]
                        },
                        {
                            'subscription_guid': '44444444-4444-4444-4444-444444444444',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'subscription_guid': '44444444-4444-4444-4444-444444444444',
                                    'total': 658.306642830709
                                }
                            ]
                        }
                    ]
                }
            ],
            'total': {
                'value': 5475.922451027388,
                'units': 'GB-Mo'
            }
        }
Пример #10
0
    def initialize_request(self, context=None):
        """Initialize model data."""
        if context:
            request_context = context.get("request_context")
            request = request_context["request"]
            serializer = UserSerializer(data=context.get("user_data"),
                                        context=request_context)
        else:
            request_context = self.request_context
            request = request_context["request"]
            serializer = UserSerializer(data=self.user_data,
                                        context=request_context)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()
            request.user = user

        provider_data = {
            "name": "test_provider",
            "type": Provider.PROVIDER_OCP.lower(),
            "authentication": {
                "provider_resource_name": self.fake.word()
            },
        }
        serializer = ProviderSerializer(data=provider_data,
                                        context=request_context)
        if serializer.is_valid(raise_exception=True):
            self.provider = serializer.save()

        self.ocp_metric = CostModelMetricsMap.OCP_METRIC_CPU_CORE_USAGE_HOUR
        self.ocp_source_type = Provider.PROVIDER_OCP
        tiered_rates = [{
            "value": round(Decimal(random.random()), 6),
            "unit": "USD",
            "usage": {
                "usage_start": None,
                "usage_end": None
            },
        }]
        self.fake_data = {
            "name":
            "Test Cost Model",
            "description":
            "Test",
            "source_type":
            self.ocp_source_type,
            "provider_uuids": [self.provider.uuid],
            "rates": [{
                "metric": {
                    "name": self.ocp_metric
                },
                "tiered_rates": tiered_rates
            }],
        }

        with tenant_context(self.tenant):
            serializer = CostModelSerializer(data=self.fake_data,
                                             context=request_context)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
Пример #11
0
    def test_user_preference_duplicate(self):
        """Test that we fail to create arbitrary preference if it already exits."""
        user = None
        serializer = UserSerializer(data=self.user_data,
                                    context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()

        kwargs = {"context": {"user": user}}
        test_pref = {"foo": ["a", [1, 2, 3], {"b": "c"}]}
        data = {
            "name": self.fake.word(),
            "description": self.fake.text(),
            "preference": test_pref
        }
        serializer = UserPreferenceSerializer(data=data, **kwargs)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

        with self.assertRaises(IntegrityError):
            serializer = UserPreferenceSerializer(data=data, **kwargs)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
Пример #12
0
class ProviderSerializer(serializers.ModelSerializer):
    """Serializer for the Provider model."""

    uuid = serializers.UUIDField(read_only=True)
    name = serializers.CharField(max_length=256, required=True,
                                 allow_null=False, allow_blank=False)
    type = serializers.ChoiceField(choices=Provider.PROVIDER_CHOICES)
    created_timestamp = serializers.DateTimeField(read_only=True)
    customer = CustomerSerializer(read_only=True)
    created_by = UserSerializer(read_only=True)

    # pylint: disable=too-few-public-methods
    class Meta:
        """Metadata for the serializer."""

        model = Provider
        fields = ('uuid', 'name', 'type', 'authentication', 'billing_source',
                  'customer', 'created_by', 'created_timestamp')

    def __init__(self, instance=None, data=empty, **kwargs):
        """Initialize the Provider Serializer.

        Here we ensure we use the appropriate serializer to validate the
        authentication and billing_source parameters.
        """
        super().__init__(instance, data, **kwargs)

        provider_type = None
        if data and data != empty:
            provider_type = data.get('type')

        if provider_type and provider_type.lower() not in PROVIDER_CHOICE_LIST:
            key = 'type'
            message = f'{provider_type} is not a valid source type.'
            raise serializers.ValidationError(error_obj(key, message))

        if provider_type:
            self.fields['authentication'] = AUTHENTICATION_SERIALIZERS.get(provider_type)()
            self.fields['billing_source'] = BILLING_SOURCE_SERIALIZERS.get(provider_type)(
                default={'bucket': '', 'data_source': {'bucket': ''}}
            )
        else:
            self.fields['authentication'] = ProviderAuthenticationSerializer()
            self.fields['billing_source'] = ProviderBillingSourceSerializer()

    @transaction.atomic
    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:
            existing_provider = Provider.objects.filter(authentication=auth)\
                .filter(billing_source=bill).first()
            if existing_provider.type in ('AWS', 'OCP'):
                sources_auth = {'resource_name': provider_resource_name}
            elif existing_provider.type in ('AZURE', ):
                sources_auth = {'credentials': auth.credentials}
            else:
                sources_auth = {}
            source_query = Sources.objects.filter(authentication=sources_auth)
            if source_query.exists():
                source_obj = source_query.first()
                source_obj.koku_uuid = existing_provider.uuid
                source_obj.save()
                return existing_provider
            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.save()
        return provider

    @transaction.atomic
    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
Пример #13
0
    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        self.data_generator = OCPReportDataGenerator(self.tenant)
        self.data_generator.add_data_to_tenant()
        serializer = UserSerializer(data=self.user_data, context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

        self.report_ocp_cpu = {
            'group_by': {
                'project': [
                    '*'
                ]
            },
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': '-1',
                'time_scope_units': 'month'
            },
            'data': [
                {
                    'date': '2018-10',
                    'projects': [
                        {
                            'project': 'default',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'default',
                                    'limit': 'null',
                                    'usage': 0.119385,
                                    'request': 9.506666
                                }
                            ]
                        },
                        {
                            'project': 'metering',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'metering',
                                    'limit': 'null',
                                    'usage': 4.464511,
                                    'request': 53.985832
                                }
                            ]
                        },
                        {
                            'project': 'monitoring',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'monitoring',
                                    'limit': 'null',
                                    'usage': 7.861343,
                                    'request': 17.920067
                                }
                            ]
                        },
                        {
                            'project': 'openshift-web-console',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'openshift-web-console',
                                    'limit': 'null',
                                    'usage': 0.862687,
                                    'request': 4.753333
                                }
                            ]
                        }
                    ]
                }
            ],
            'total': {
                'pod_usage_cpu_core_hours': 13.307928,
                'pod_request_cpu_core_hours': 86.165898
            }
        }
        self.report_ocp_mem = {
            'group_by': {
                'project': [
                    '*'
                ]
            },
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': '-1',
                'time_scope_units': 'month'
            },
            'data': [
                {
                    'date': '2018-10',
                    'projects': [
                        {
                            'project': 'default',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'default',
                                    'memory_usage_gigabytes': 0.162249,
                                    'memory_requests_gigabytes': 1.063302
                                }
                            ]
                        },
                        {
                            'project': 'metering',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'metering',
                                    'memory_usage_gigabytes': 5.899788,
                                    'memory_requests_gigabytes': 7.007081
                                }
                            ]
                        },
                        {
                            'project': 'monitoring',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'monitoring',
                                    'memory_usage_gigabytes': 3.178287,
                                    'memory_requests_gigabytes': 4.153526
                                }
                            ]
                        },
                        {
                            'project': 'openshift-web-console',
                            'values': [
                                {
                                    'date': '2018-10',
                                    'project': 'openshift-web-console',
                                    'memory_usage_gigabytes': 0.068988,
                                    'memory_requests_gigabytes': 0.207677
                                }
                            ]
                        }
                    ]
                }
            ],
            'total': {
                'pod_usage_memory_gigabytes': 9.309312,
                'pod_request_memory_gigabytes': 12.431585
            }
        }
Пример #14
0
    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        serializer = UserSerializer(data=self.user_data,
                                    context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

        self.report = {
            "group_by": {
                "subscription_guid": ["*"]
            },
            "filter": {
                "resolution": "monthly",
                "time_scope_value": -1,
                "time_scope_units": "month",
                "resource_scope": [],
            },
            "data": [{
                "date":
                "2018-07",
                "subscription_guids": [
                    {
                        "subscription_guid":
                        "00000000-0000-0000-0000-000000000000",
                        "values": [{
                            "date": "2018-07",
                            "units": "GB-Mo",
                            "subscription_guid":
                            "00000000-0000-0000-0000-000000000000",
                            "total": 1826.74238146924,
                        }],
                    },
                    {
                        "subscription_guid":
                        "11111111-1111-1111-1111-111111111111",
                        "values": [{
                            "date": "2018-07",
                            "units": "GB-Mo",
                            "subscription_guid":
                            "11111111-1111-1111-1111-111111111111",
                            "total": 1137.74036198065,
                        }],
                    },
                    {
                        "subscription_guid":
                        "22222222-2222-2222-2222-222222222222",
                        "values": [{
                            "date": "2018-07",
                            "units": "GB-Mo",
                            "subscription_guid":
                            "22222222-2222-2222-2222-222222222222",
                            "total": 1045.80659412797,
                        }],
                    },
                    {
                        "subscription_guid":
                        "33333333-3333-3333-3333-333333333333",
                        "values": [{
                            "date": "2018-07",
                            "units": "GB-Mo",
                            "subscription_guid":
                            "33333333-3333-3333-3333-333333333333",
                            "total": 807.326470618818,
                        }],
                    },
                    {
                        "subscription_guid":
                        "44444444-4444-4444-4444-444444444444",
                        "values": [{
                            "date": "2018-07",
                            "units": "GB-Mo",
                            "subscription_guid":
                            "44444444-4444-4444-4444-444444444444",
                            "total": 658.306642830709,
                        }],
                    },
                ],
            }],
            "total": {
                "value": 5475.922451027388,
                "units": "GB-Mo"
            },
        }
Пример #15
0
    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        serializer = UserSerializer(data=self.user_data, context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
        self.client = APIClient()

        self.report = {
            "group_by": {"account": ["*"]},
            "filter": {
                "resolution": "monthly",
                "time_scope_value": -1,
                "time_scope_units": "month",
                "resource_scope": [],
            },
            "data": [
                {
                    "date": "2018-07",
                    "accounts": [
                        {
                            "account": "4418636104713",
                            "values": [
                                {
                                    "date": "2018-07",
                                    "units": "GB-Mo",
                                    "account": "4418636104713",
                                    "total": 1826.74238146924,
                                }
                            ],
                        },
                        {
                            "account": "8577742690384",
                            "values": [
                                {
                                    "date": "2018-07",
                                    "units": "GB-Mo",
                                    "account": "8577742690384",
                                    "total": 1137.74036198065,
                                }
                            ],
                        },
                        {
                            "account": "3474227945050",
                            "values": [
                                {
                                    "date": "2018-07",
                                    "units": "GB-Mo",
                                    "account": "3474227945050",
                                    "total": 1045.80659412797,
                                }
                            ],
                        },
                        {
                            "account": "7249815104968",
                            "values": [
                                {
                                    "date": "2018-07",
                                    "units": "GB-Mo",
                                    "account": "7249815104968",
                                    "total": 807.326470618818,
                                }
                            ],
                        },
                        {
                            "account": "9420673783214",
                            "values": [
                                {
                                    "date": "2018-07",
                                    "units": "GB-Mo",
                                    "account": "9420673783214",
                                    "total": 658.306642830709,
                                }
                            ],
                        },
                    ],
                }
            ],
            "total": {"value": 5475.922451027388, "units": "GB-Mo"},
        }
Пример #16
0
class ProviderSerializer(serializers.ModelSerializer):
    """Serializer for the Provider model."""

    uuid = serializers.UUIDField(allow_null=True, required=False)
    name = serializers.CharField(max_length=256,
                                 required=True,
                                 allow_null=False,
                                 allow_blank=False)
    type = serializers.ChoiceField(choices=LCASE_PROVIDER_CHOICE_LIST)
    created_timestamp = serializers.DateTimeField(read_only=True)
    customer = CustomerSerializer(read_only=True)
    created_by = UserSerializer(read_only=True)
    active = serializers.BooleanField(read_only=True)
    paused = serializers.BooleanField(required=False)

    class Meta:
        """Metadata for the serializer."""

        model = Provider
        fields = (
            "uuid",
            "name",
            "type",
            "authentication",
            "billing_source",
            "customer",
            "created_by",
            "created_timestamp",
            "active",
            "paused",
        )

    def __init__(self, instance=None, data=empty, **kwargs):
        """Initialize the Provider Serializer.

        Here we ensure we use the appropriate serializer to validate the
        authentication and billing_source parameters.
        """
        super().__init__(instance, data, **kwargs)

        provider_type = None
        if data and data != empty:
            provider_type = data.get("type")

        if provider_type and provider_type.lower(
        ) not in LCASE_PROVIDER_CHOICE_LIST:
            key = "type"
            message = f"{provider_type} is not a valid source type."
            raise serializers.ValidationError(error_obj(key, message))

        if provider_type:
            provider_type = provider_type.lower()
            self.fields["authentication"] = AUTHENTICATION_SERIALIZERS.get(
                Provider.PROVIDER_CASE_MAPPING.get(provider_type))()
            self.fields["billing_source"] = BILLING_SOURCE_SERIALIZERS.get(
                Provider.PROVIDER_CASE_MAPPING.get(provider_type))()
        else:
            self.fields["authentication"] = ProviderAuthenticationSerializer()
            self.fields["billing_source"] = ProviderBillingSourceSerializer()

    @property
    def demo_credentials(self):
        """Build formatted credentials for our nise-populator demo accounts."""
        creds_by_source_type = defaultdict(list)
        for account, cred_dict in settings.DEMO_ACCOUNTS.items():
            for cred, info in cred_dict.items():
                if info.get("source_type") == Provider.PROVIDER_AWS:
                    creds_by_source_type[Provider.PROVIDER_AWS].append(
                        {"role_arn": cred})
                elif info.get("source_type") == Provider.PROVIDER_AZURE:
                    creds_by_source_type[Provider.PROVIDER_AZURE].append(
                        {"client_id": cred})
                elif info.get("source_type") == Provider.PROVIDER_GCP:
                    creds_by_source_type[Provider.PROVIDER_GCP].append(
                        {"project_id": cred})
        return creds_by_source_type

    def get_request_info(self):
        """Obtain request information like user and customer context."""
        user = self.context.get("user")
        customer = self.context.get("customer")
        if user and customer:
            return user, customer

        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))
        return user, customer

    @transaction.atomic
    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 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 _is_demo_account(self, provider_type, credentials):
        """Test whether this source is a demo account."""
        key_types = {
            Provider.PROVIDER_AWS: "role_arn",
            Provider.PROVIDER_AZURE: "client_id",
            Provider.PROVIDER_GCP: "project_id",
        }

        key_to_check = key_types.get(provider_type, "")
        creds_to_check = self.demo_credentials.get(provider_type, [])
        for cred in creds_to_check:
            if credentials.get(key_to_check,
                               True) == cred.get(key_to_check, False):
                return True
        return False
Пример #17
0
    def initialize_request(self, context=None):
        """Initialize model data."""
        if context:
            request_context = context.get('request_context')
            request = request_context['request']
            serializer = UserSerializer(data=context.get('user_data'),
                                        context=request_context)
        else:
            request_context = self.request_context
            request = request_context['request']
            serializer = UserSerializer(data=self.user_data,
                                        context=request_context)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()
            request.user = user

        provider_data = {
            'name': 'test_provider',
            'type': Provider.PROVIDER_OCP,
            'authentication': {
                'provider_resource_name': self.fake.word()
            }
        }
        serializer = ProviderSerializer(data=provider_data,
                                        context=request_context)
        if serializer.is_valid(raise_exception=True):
            self.provider = serializer.save()

        self.ocp_metric = CostModelMetricsMap.OCP_METRIC_CPU_CORE_USAGE_HOUR
        self.ocp_source_type = 'OCP'
        tiered_rates = [{
            'value': round(Decimal(random.random()), 6),
            'unit': 'USD',
            'usage': {
                'usage_start': None,
                'usage_end': None
            }
        }]
        self.fake_data = {
            'name':
            'Test Cost Model',
            'description':
            'Test',
            'source_type':
            self.ocp_source_type,
            'provider_uuids': [self.provider.uuid],
            'rates': [{
                'metric': {
                    'name': self.ocp_metric
                },
                'tiered_rates': tiered_rates
            }]
        }

        with tenant_context(self.tenant):
            serializer = CostModelSerializer(data=self.fake_data,
                                             context=request_context)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
Пример #18
0
class ProviderSerializer(serializers.ModelSerializer):
    """Serializer for the Provider  model."""

    uuid = serializers.UUIDField(read_only=True)
    name = serializers.CharField(max_length=256,
                                 required=True,
                                 allow_null=False,
                                 allow_blank=False)
    type = serializers.ChoiceField(choices=Provider.PROVIDER_CHOICES)
    authentication = ProviderAuthenticationSerializer()
    billing_source = ProviderBillingSourceSerializer(default={'bucket': ''})
    customer = CustomerSerializer(read_only=True)
    created_by = UserSerializer(read_only=True)

    class Meta:
        """Metadata for the serializer."""

        model = Provider
        fields = ('uuid', 'name', 'type', 'authentication', 'billing_source',
                  'customer', 'created_by')

    @transaction.atomic
    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')
            bucket = billing_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': ''}
        authentication = validated_data.pop('authentication')
        provider_resource_name = authentication.get('provider_resource_name')
        provider_type = validated_data['type']
        interface = ProviderAccessor(provider_type)
        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.save()
        return provider
Пример #19
0
    def test_user_preference_duplicate(self):
        """Test that we fail to create arbitrary preference if it already exits."""
        user = None
        serializer = UserSerializer(data=self.user_data,
                                    context=self.request_context)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()

        kwargs = {'context': {'user': user}}
        test_pref = {'foo': ['a', [1, 2, 3], {'b': 'c'}]}
        data = {
            'name': self.fake.word(),
            'description': self.fake.text(),
            'preference': test_pref
        }
        serializer = UserPreferenceSerializer(data=data, **kwargs)
        if serializer.is_valid(raise_exception=True):
            serializer.save()

        with self.assertRaises(IntegrityError):
            serializer = UserPreferenceSerializer(data=data, **kwargs)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
Пример #20
0
class ProviderSerializer(serializers.ModelSerializer):
    """Serializer for the Provider  model."""

    uuid = serializers.UUIDField(read_only=True)
    name = serializers.CharField(max_length=256,
                                 required=True,
                                 allow_null=False,
                                 allow_blank=False)
    type = serializers.ChoiceField(choices=Provider.PROVIDER_CHOICES)
    authentication = ProviderAuthenticationSerializer()
    billing_source = ProviderBillingSourceSerializer()
    customer = CustomerSerializer(read_only=True)
    created_by = UserSerializer(read_only=True)

    class Meta:
        """Metadata for the serializer."""

        model = Provider
        fields = ('uuid', 'name', 'type', 'authentication', 'billing_source',
                  'customer', 'created_by')

    @transaction.atomic
    def create(self, validated_data):
        """Create a user 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')
        access_key_id, secret_access_key, session_token = _get_sts_access(
            provider_resource_name)
        if (access_key_id is None or access_key_id is None
                or session_token is None):
            key = 'provider_resource_name'
            message = 'Unable to obtain credentials with using {}.'.format(
                provider_resource_name)
            raise serializers.ValidationError(error_obj(key, message))

        s3_exists = _check_s3_access(access_key_id, secret_access_key,
                                     session_token, bucket)
        if not s3_exists:
            key = 'bucket'
            message = 'Bucket {} could not be found with {}.'.format(
                bucket, provider_resource_name)
            raise serializers.ValidationError(error_obj(key, message))

        org_access = _check_org_access(access_key_id, secret_access_key,
                                       session_token)
        if not org_access:
            key = 'provider_resource_name'
            message = 'Unable to obtain organization data with {}.'.format(
                provider_resource_name)
            LOG.info(message)

        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