<commit_before># -*- coding: utf-8 -*-

# Copyright 2014,  Digital Reasoning
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


import logging

import yaml
from rest_framework import generics, status
from rest_framework.filters import DjangoFilterBackend, DjangoObjectPermissionsFilter
from rest_framework.response import Response

from blueprints.serializers import BlueprintSerializer
from core.exceptions import BadRequest, ResourceConflict
from core.permissions import StackdioModelPermissions, StackdioObjectPermissions
from . import filters, mixins, models, permissions, serializers


logger = logging.getLogger(__name__)


class CloudProviderTypeListAPIView(generics.ListAPIView):
    queryset = models.CloudProviderType.objects.all()
    serializer_class = serializers.CloudProviderTypeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudProviderTypeDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudProviderType.objects.all()
    serializer_class = serializers.CloudProviderTypeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudProviderListAPIView(generics.ListCreateAPIView):
    queryset = models.CloudProvider.objects.all()
    serializer_class = serializers.CloudProviderSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)
    filter_class = filters.CloudProviderFilter

    def perform_create(self, serializer):

        data = self.request.DATA
        files = self.request.FILES

        # Lookup provider type
        try:
            obj = serializer.save()
            driver = obj.get_driver()

            # Leverage the driver to generate its required data that
            # will be serialized down to yaml and stored in both the database
            # and the salt cloud providers file
            provider_data = driver.get_provider_data(data, files)

            # Generate the yaml and store in the database
            yaml_data = {
                obj.slug: provider_data
            }
            obj.yaml = yaml.safe_dump(yaml_data, default_flow_style=False)
            obj.save()

            # Update the salt cloud providers file
            obj.update_config()

        except models.CloudProviderType.DoesNotExist:
            err_msg = 'Given provider type does not exist.'
            logger.exception(err_msg)
            raise BadRequest(err_msg)


class CloudProviderDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.CloudProvider.objects.all()
    serializer_class = serializers.CloudProviderSerializer
    permission_classes = (StackdioObjectPermissions,)

    def destroy(self, request, *args, **kwargs):
        # check for profiles using this provider before deleting
        profiles = set(self.get_object().profiles.all())
        if profiles:
            profiles = serializers.CloudProfileSerializer(
                profiles,
                context={'request': request}).data
            return Response({
                'detail': 'One or more profiles are making use of this '
                          'provider.',
                'profiles': profiles,
            }, status=status.HTTP_400_BAD_REQUEST)

        # ask the driver to clean up after itsef since it's no longer needed
        driver = self.get_object().get_driver()
        driver.destroy()

        return super(CloudProviderDetailAPIView, self).destroy(request, *args, **kwargs)


class GlobalOrchestrationComponentListAPIView(mixins.CloudProviderRelatedMixin,
                                              generics.ListCreateAPIView):
    serializer_class = serializers.GlobalOrchestrationFormulaComponentSerializer

    def get_queryset(self):
        return self.get_provider().global_formula_components.all()

    def perform_create(self, serializer):
        serializer.save(provider=self.get_provider())

    def create(self, request, *args, **kwargs):
        component_id = request.DATA.get('component')
        try:
            # Delete an existing component if there is one
            component = self.get_queryset().get(component__id=component_id)
            component.delete()
        except models.GlobalOrchestrationFormulaComponent.DoesNotExist:
            pass

        return super(GlobalOrchestrationComponentListAPIView, self).create(request, *args, **kwargs)


class GlobalOrchestrationComponentDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.GlobalOrchestrationFormulaComponent.objects.all()
    serializer_class = serializers.GlobalOrchestrationFormulaComponentSerializer
    permission_classes = (StackdioObjectPermissions,)


class GlobalOrchestrationPropertiesAPIView(mixins.CloudProviderRelatedMixin,
                                           generics.RetrieveUpdateAPIView):
    queryset = models.CloudProvider.objects.all()
    serializer_class = serializers.GlobalOrchestrationPropertiesSerializer


class CloudProviderVPCSubnetListAPIView(mixins.CloudProviderRelatedMixin, generics.ListAPIView):
    def list(self, request, *args, **kwargs):
        provider = self.get_provider()
        driver = provider.get_driver()

        subnets = driver.get_vpc_subnets()
        return Response({
            'results': serializers.VPCSubnetSerializer(subnets, many=True).data
        })


class CloudInstanceSizeListAPIView(generics.ListAPIView):
    queryset = models.CloudInstanceSize.objects.all()
    serializer_class = serializers.CloudInstanceSizeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudInstanceSizeFilter


class CloudInstanceSizeDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudInstanceSize.objects.all()
    serializer_class = serializers.CloudInstanceSizeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudProfileListAPIView(generics.ListCreateAPIView):
    queryset = models.CloudProfile.objects.all()
    serializer_class = serializers.CloudProfileSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)
    filter_class = filters.CloudProfileFilter

    def perform_create(self, serializer):
        obj = serializer.save()
        obj.update_config()


class CloudProfileDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.CloudProfile.objects.all()
    serializer_class = serializers.CloudProfileSerializer
    permission_classes = (StackdioObjectPermissions,)

    def update(self, request, *args, **kwargs):
        # validate that the AMI exists by looking it up in the cloud provider
        if 'image_id' in request.DATA:
            driver = self.get_object().cloud_provider.get_driver()
            result, error = driver.has_image(request.DATA['image_id'])
            if not result:
                raise BadRequest(error)

        # Perform the update
        ret = super(CloudProfileDetailAPIView, self).update(request,
                                                            *args,
                                                            **kwargs)

        # Regenerate the profile config file
        profile = self.get_object()
        profile.update_config()
        return ret

    def destroy(self, request, *args, **kwargs):
        # check for blueprint usage before deleting
        blueprints = set([hd.blueprint
                          for hd in self.get_object().host_definitions.all()])
        if blueprints:
            blueprints = BlueprintSerializer(blueprints,
                                             context={'request': request}).data
            return Response({
                'detail': 'One or more blueprints are making use of this '
                          'profile.',
                'blueprints': blueprints,
            }, status=status.HTTP_400_BAD_REQUEST)

        return super(CloudProfileDetailAPIView, self).destroy(request,
                                                              *args,
                                                              **kwargs)


class SnapshotListAPIView(generics.ListCreateAPIView):
    queryset = models.Snapshot.objects.all()
    serializer_class = serializers.SnapshotSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)


class SnapshotDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.Snapshot.objects.all()
    serializer_class = serializers.SnapshotSerializer
    permission_classes = (StackdioObjectPermissions,)


class CloudRegionListAPIView(generics.ListAPIView):
    queryset = models.CloudRegion.objects.all()
    serializer_class = serializers.CloudRegionSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudRegionFilter


class CloudRegionDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudRegion.objects.all()
    serializer_class = serializers.CloudRegionSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudRegionZoneListAPIView(generics.ListAPIView):
    queryset = models.CloudZone.objects.all()
    serializer_class = serializers.CloudZoneSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudZoneFilter

    def get_queryset(self):
        return models.CloudZone.objects.filter(region__id=self.kwargs['pk'])


class CloudZoneListAPIView(generics.ListAPIView):
    queryset = models.CloudZone.objects.all()
    serializer_class = serializers.CloudZoneSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudZoneFilter


class CloudZoneDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudZone.objects.all()
    serializer_class = serializers.CloudZoneSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class SecurityGroupListAPIView(generics.ListCreateAPIView):
    """
    Lists and creates new security groups.

    ### GET

    Retrieves all security groups owned by the authenticated user.
    The associated rules for each group will also be given in the
    `rules` attribute. The `active_hosts` field will also be
    updated to show the number of hosts known by stackd.io to be
    using the security group at this time, but please **note**
    that other machines in the cloud provider could be using
    the same security group and stackd.io may not be aware.

    ### POST

    Creates a new security group given the following properties
    in the JSON request:

    `name` -- The name of the security group. This will also be
              used to create the security group on the provider.

    `description` -- The description or purpose of the group.

    `cloud_provider` -- The id of the cloud provider to associate
                        this group with.

    `is_default` -- Boolean representing if this group, for this
                    provider, is set to automatically be added
                    to all hosts launched on the provider. **NOTE**
                    this property may only be set by an admin.
    """
    queryset = models.SecurityGroup.objects.all().with_rules()
    serializer_class = serializers.SecurityGroupSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)
    filter_class = filters.SecurityGroupFilter

    # TODO: Ignore code complexity issues
    def create(self, request, *args, **kwargs):  # NOQA
        name = request.DATA.get('name')
        group_id = request.DATA.get('group_id')
        description = request.DATA.get('description')
        provider_id = request.DATA.get('cloud_provider')
        is_default = request.DATA.get('is_default', False)
        owner = request.user

        if not owner.is_superuser:
            is_default = False
        elif not isinstance(is_default, bool):
            is_default = False

        provider = models.CloudProvider.objects.get(id=provider_id)
        driver = provider.get_driver()

        # check if the group already exists in our DB first
        try:
            models.SecurityGroup.objects.get(
                name=name,
                group_id=group_id,
                cloud_provider=provider
            )
            raise ResourceConflict('Security group already exists')
        except models.SecurityGroup.DoesNotExist:
            # doesn't exist in our database
            pass

        # check if the group exists on the provider
        provider_group = None
        if group_id:
            try:
                provider_group = driver.get_security_groups([group_id])[name]
                logger.debug('Security group already exists on the '
                             'provider: {0!r}'.format(provider_group))

            except KeyError:
                raise
            except:
                # doesn't exist on the provider either, we'll create it now
                provider_group = None

        # admin is using an existing group, use the existing group id
        if provider_group:
            group_id = provider_group['group_id']
            description = provider_group['description']
        else:
            # create a new group
            group_id = driver.create_security_group(name, description)

        # create a new group in the DB
        group_obj = models.SecurityGroup.objects.create(
            name=name,
            description=description,
            group_id=group_id,
            cloud_provider=provider,
            owner=owner,
            is_default=is_default
        )

        # if an admin and the security group is_default, we need to make sure
        # the cloud provider configuration is properly maintained
        if owner.is_superuser and is_default:
            logger.debug('Writing cloud providers file because new security '
                         'group was added with is_default flag set to True')
            provider.update_config()

        serializer = serializers.SecurityGroupSerializer(group_obj, context={
            'request': request
        })
        return Response(serializer.data)<commit_msg>PI-460 removed reference to owner in security group endpoint<commit_after># -*- coding: utf-8 -*-

# Copyright 2014,  Digital Reasoning
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


import logging

import yaml
from rest_framework import generics, status
from rest_framework.filters import DjangoFilterBackend, DjangoObjectPermissionsFilter
from rest_framework.response import Response

from blueprints.serializers import BlueprintSerializer
from core.exceptions import BadRequest, ResourceConflict
from core.permissions import StackdioModelPermissions, StackdioObjectPermissions
from . import filters, mixins, models, permissions, serializers


logger = logging.getLogger(__name__)


class CloudProviderTypeListAPIView(generics.ListAPIView):
    queryset = models.CloudProviderType.objects.all()
    serializer_class = serializers.CloudProviderTypeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudProviderTypeDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudProviderType.objects.all()
    serializer_class = serializers.CloudProviderTypeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudProviderListAPIView(generics.ListCreateAPIView):
    queryset = models.CloudProvider.objects.all()
    serializer_class = serializers.CloudProviderSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)
    filter_class = filters.CloudProviderFilter

    def perform_create(self, serializer):

        data = self.request.DATA
        files = self.request.FILES

        # Lookup provider type
        try:
            obj = serializer.save()
            driver = obj.get_driver()

            # Leverage the driver to generate its required data that
            # will be serialized down to yaml and stored in both the database
            # and the salt cloud providers file
            provider_data = driver.get_provider_data(data, files)

            # Generate the yaml and store in the database
            yaml_data = {
                obj.slug: provider_data
            }
            obj.yaml = yaml.safe_dump(yaml_data, default_flow_style=False)
            obj.save()

            # Update the salt cloud providers file
            obj.update_config()

        except models.CloudProviderType.DoesNotExist:
            err_msg = 'Given provider type does not exist.'
            logger.exception(err_msg)
            raise BadRequest(err_msg)


class CloudProviderDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.CloudProvider.objects.all()
    serializer_class = serializers.CloudProviderSerializer
    permission_classes = (StackdioObjectPermissions,)

    def destroy(self, request, *args, **kwargs):
        # check for profiles using this provider before deleting
        profiles = set(self.get_object().profiles.all())
        if profiles:
            profiles = serializers.CloudProfileSerializer(
                profiles,
                context={'request': request}).data
            return Response({
                'detail': 'One or more profiles are making use of this '
                          'provider.',
                'profiles': profiles,
            }, status=status.HTTP_400_BAD_REQUEST)

        # ask the driver to clean up after itsef since it's no longer needed
        driver = self.get_object().get_driver()
        driver.destroy()

        return super(CloudProviderDetailAPIView, self).destroy(request, *args, **kwargs)


class GlobalOrchestrationComponentListAPIView(mixins.CloudProviderRelatedMixin,
                                              generics.ListCreateAPIView):
    serializer_class = serializers.GlobalOrchestrationFormulaComponentSerializer

    def get_queryset(self):
        return self.get_provider().global_formula_components.all()

    def perform_create(self, serializer):
        serializer.save(provider=self.get_provider())

    def create(self, request, *args, **kwargs):
        component_id = request.DATA.get('component')
        try:
            # Delete an existing component if there is one
            component = self.get_queryset().get(component__id=component_id)
            component.delete()
        except models.GlobalOrchestrationFormulaComponent.DoesNotExist:
            pass

        return super(GlobalOrchestrationComponentListAPIView, self).create(request, *args, **kwargs)


class GlobalOrchestrationComponentDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.GlobalOrchestrationFormulaComponent.objects.all()
    serializer_class = serializers.GlobalOrchestrationFormulaComponentSerializer
    permission_classes = (StackdioObjectPermissions,)


class GlobalOrchestrationPropertiesAPIView(mixins.CloudProviderRelatedMixin,
                                           generics.RetrieveUpdateAPIView):
    queryset = models.CloudProvider.objects.all()
    serializer_class = serializers.GlobalOrchestrationPropertiesSerializer


class CloudProviderVPCSubnetListAPIView(mixins.CloudProviderRelatedMixin, generics.ListAPIView):
    def list(self, request, *args, **kwargs):
        provider = self.get_provider()
        driver = provider.get_driver()

        subnets = driver.get_vpc_subnets()
        return Response({
            'results': serializers.VPCSubnetSerializer(subnets, many=True).data
        })


class CloudInstanceSizeListAPIView(generics.ListAPIView):
    queryset = models.CloudInstanceSize.objects.all()
    serializer_class = serializers.CloudInstanceSizeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudInstanceSizeFilter


class CloudInstanceSizeDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudInstanceSize.objects.all()
    serializer_class = serializers.CloudInstanceSizeSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudProfileListAPIView(generics.ListCreateAPIView):
    queryset = models.CloudProfile.objects.all()
    serializer_class = serializers.CloudProfileSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)
    filter_class = filters.CloudProfileFilter

    def perform_create(self, serializer):
        obj = serializer.save()
        obj.update_config()


class CloudProfileDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.CloudProfile.objects.all()
    serializer_class = serializers.CloudProfileSerializer
    permission_classes = (StackdioObjectPermissions,)

    def update(self, request, *args, **kwargs):
        # validate that the AMI exists by looking it up in the cloud provider
        if 'image_id' in request.DATA:
            driver = self.get_object().cloud_provider.get_driver()
            result, error = driver.has_image(request.DATA['image_id'])
            if not result:
                raise BadRequest(error)

        # Perform the update
        ret = super(CloudProfileDetailAPIView, self).update(request,
                                                            *args,
                                                            **kwargs)

        # Regenerate the profile config file
        profile = self.get_object()
        profile.update_config()
        return ret

    def destroy(self, request, *args, **kwargs):
        # check for blueprint usage before deleting
        blueprints = set([hd.blueprint
                          for hd in self.get_object().host_definitions.all()])
        if blueprints:
            blueprints = BlueprintSerializer(blueprints,
                                             context={'request': request}).data
            return Response({
                'detail': 'One or more blueprints are making use of this '
                          'profile.',
                'blueprints': blueprints,
            }, status=status.HTTP_400_BAD_REQUEST)

        return super(CloudProfileDetailAPIView, self).destroy(request,
                                                              *args,
                                                              **kwargs)


class SnapshotListAPIView(generics.ListCreateAPIView):
    queryset = models.Snapshot.objects.all()
    serializer_class = serializers.SnapshotSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)


class SnapshotDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.Snapshot.objects.all()
    serializer_class = serializers.SnapshotSerializer
    permission_classes = (StackdioObjectPermissions,)


class CloudRegionListAPIView(generics.ListAPIView):
    queryset = models.CloudRegion.objects.all()
    serializer_class = serializers.CloudRegionSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudRegionFilter


class CloudRegionDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudRegion.objects.all()
    serializer_class = serializers.CloudRegionSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class CloudRegionZoneListAPIView(generics.ListAPIView):
    queryset = models.CloudZone.objects.all()
    serializer_class = serializers.CloudZoneSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudZoneFilter

    def get_queryset(self):
        return models.CloudZone.objects.filter(region__id=self.kwargs['pk'])


class CloudZoneListAPIView(generics.ListAPIView):
    queryset = models.CloudZone.objects.all()
    serializer_class = serializers.CloudZoneSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)
    filter_class = filters.CloudZoneFilter


class CloudZoneDetailAPIView(generics.RetrieveAPIView):
    queryset = models.CloudZone.objects.all()
    serializer_class = serializers.CloudZoneSerializer
    permission_classes = (permissions.StackdioReadOnlyModelPermissions,)


class SecurityGroupListAPIView(generics.ListCreateAPIView):
    """
    Lists and creates new security groups.

    ### GET

    Retrieves all security groups owned by the authenticated user.
    The associated rules for each group will also be given in the
    `rules` attribute. The `active_hosts` field will also be
    updated to show the number of hosts known by stackd.io to be
    using the security group at this time, but please **note**
    that other machines in the cloud provider could be using
    the same security group and stackd.io may not be aware.

    ### POST

    Creates a new security group given the following properties
    in the JSON request:

    `name` -- The name of the security group. This will also be
              used to create the security group on the provider.

    `description` -- The description or purpose of the group.

    `cloud_provider` -- The id of the cloud provider to associate
                        this group with.

    `is_default` -- Boolean representing if this group, for this
                    provider, is set to automatically be added
                    to all hosts launched on the provider. **NOTE**
                    this property may only be set by an admin.
    """
    queryset = models.SecurityGroup.objects.all().with_rules()
    serializer_class = serializers.SecurityGroupSerializer
    permission_classes = (StackdioModelPermissions,)
    filter_backends = (DjangoObjectPermissionsFilter, DjangoFilterBackend)
    filter_class = filters.SecurityGroupFilter

    # TODO: Ignore code complexity issues
    def create(self, request, *args, **kwargs):  # NOQA
        name = request.DATA.get('name')
        group_id = request.DATA.get('group_id')
        description = request.DATA.get('description')
        provider_id = request.DATA.get('cloud_provider')
        is_default = request.DATA.get('is_default', False)

        if not request.user.is_superuser:
            is_default = False
        elif not isinstance(is_default, bool):
            is_default = False

        provider = models.CloudProvider.objects.get(id=provider_id)
        driver = provider.get_driver()

        # check if the group already exists in our DB first
        try:
            models.SecurityGroup.objects.get(
                name=name,
                group_id=group_id,
                cloud_provider=provider
            )
            raise ResourceConflict('Security group already exists')
        except models.SecurityGroup.DoesNotExist:
            # doesn't exist in our database
            pass

        # check if the group exists on the provider
        provider_group = None
        if group_id:
            try:
                provider_group = driver.get_security_groups([group_id])[name]
                logger.debug('Security group already exists on the '
                             'provider: {0!r}'.format(provider_group))

            except KeyError:
                raise
            except:
                # doesn't exist on the provider either, we'll create it now
                provider_group = None

        # admin is using an existing group, use the existing group id
        if provider_group:
            group_id = provider_group['group_id']
            description = provider_group['description']
        else:
            # create a new group
            group_id = driver.create_security_group(name, description)

        # create a new group in the DB
        group_obj = models.SecurityGroup.objects.create(
            name=name,
            description=description,
            group_id=group_id,
            cloud_provider=provider,
            is_default=is_default
        )

        # if an admin and the security group is_default, we need to make sure
        # the cloud provider configuration is properly maintained
        if request.user.is_superuser and is_default:
            logger.debug('Writing cloud providers file because new security '
                         'group was added with is_default flag set to True')
            provider.update_config()

        serializer = serializers.SecurityGroupSerializer(group_obj, context={
            'request': request
        })
        return Response(serializer.data)
{'fraction_non_alphanumeric': 0.06967061746633986, 'fraction_numerical': 0.0011751670416009132, 'mean_word_length': 2.844585000645411, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2447749', 'n_tokens_mistral': 7416, 'n_tokens_neox': 7238, 'n_words': 1912}