class ProjectApplicationSerializer(serializers.HyperlinkedModelSerializer):
    project = ModelRelatedField(queryset=Project.objects.all(),
                                serializer_class=ProjectSummarySerializer,
                                style={'base_template': 'input.html'})
    image = ModelRelatedField(queryset=Application.objects.all(),
                              serializer_class=ImageSummarySerializer,
                              style={'base_template': 'input.html'},
                              source='application')
    url = serializers.HyperlinkedIdentityField(
        view_name='api:v2:projectapplication-detail', )

    class Meta:
        model = ProjectApplication
        validators = [
            # TODO: Fix that 'application' leaks into real-world here.
            UniqueTogetherValidator(queryset=ProjectApplication.objects.all(),
                                    fields=('project', 'application')),
        ]
        fields = ('id', 'url', 'project', 'image')
class InstanceAllocationSourceSerializer(serializers.HyperlinkedModelSerializer
                                         ):
    allocation_source = ModelRelatedField(
        queryset=AllocationSource.objects.all(),
        serializer_class=AllocationSourceSerializer,
        style={'base_template': 'input.html'})
    instance = ModelRelatedField(queryset=Instance.objects.all(),
                                 serializer_class=InstanceSerializer,
                                 style={'base_template': 'input.html'})
    url = serializers.HyperlinkedIdentityField(
        view_name='api:v2:instance-allocation-source-detail', )

    class Meta:
        model = InstanceAllocationSourceSnapshot
        validators = [
            UniqueTogetherValidator(
                queryset=InstanceAllocationSourceSnapshot.objects.all(),
                fields=('instance', 'allocation_source')),
        ]
        fields = ('id', 'url', 'instance', 'allocation_source')
class PatternMatchSerializer(serializers.HyperlinkedModelSerializer):
    type = serializers.SlugRelatedField(queryset=MatchType.objects.all(),
                                        slug_field='name')
    created_by = ModelRelatedField(lookup_field="username",
                                   default=serializers.CurrentUserDefault(),
                                   queryset=AtmosphereUser.objects.all(),
                                   serializer_class=UserSummarySerializer,
                                   style={'base_template': 'input.html'})
    url = serializers.HyperlinkedIdentityField(
        view_name='api:v2:patternmatch-detail', )

    class Meta:
        model = PatternMatch
        fields = ('id', 'url', 'pattern', 'type', 'created_by', 'allow_access')
class ResourceRequestSerializer(serializers.HyperlinkedModelSerializer):
    uuid = serializers.CharField(read_only=True)
    url = UUIDHyperlinkedIdentityField(
        view_name='api:v2:resourcerequest-detail', )
    created_by = UserSummarySerializer(read_only=True)
    status = ModelRelatedField(
        default=lambda: get_status_type(status="pending"),
        serializer_class=StatusTypeSummarySerializer,
        queryset=StatusType.objects.all(),
        lookup_field='id')

    class Meta:
        model = ResourceRequest
        fields = ('id', 'uuid', 'url', 'request', 'description', 'status',
                  'created_by', 'admin_message', 'start_date')
class MaintenanceRecordSerializer(serializers.HyperlinkedModelSerializer):
    provider = ModelRelatedField(lookup_field='name',
                                 queryset=Provider.objects.all(),
                                 serializer_class=ProviderSummarySerializer,
                                 style={'base_template': 'input.html'},
                                 required=False,
                                 allow_null=True)
    url = serializers.HyperlinkedIdentityField(
        view_name='api:v2:maintenancerecord-detail',
        read_only=True,
    )

    class Meta:
        model = MaintenanceRecord
        fields = ('id', 'url', 'start_date', 'end_date', 'title', 'message',
                  'provider', 'disable_login')
class UserMachineRequestSerializer(serializers.HyperlinkedModelSerializer):

    uuid = serializers.CharField(read_only=True)
    instance = ModelRelatedField(queryset=Instance.objects.all(),
                                 serializer_class=InstanceSummarySerializer,
                                 style={'base_template': 'input.html'})
    status = StatusTypeRelatedField(queryset=StatusType.objects.none(),
                                    allow_null=True,
                                    required=False)
    old_status = serializers.CharField(required=False)
    new_version_tags = serializers.CharField(required=False, allow_blank=True)
    new_version_change_log = serializers.CharField(required=False,
                                                   allow_blank=True)
    new_version_memory_min = serializers.CharField()
    new_version_cpu_min = serializers.CharField()
    new_application_name = serializers.CharField(
        validators=[NoSpecialCharacters('!"#$%&\'*+,/;<=>?@[\\]^`{|}~')])
    new_application_version = ImageVersionSummarySerializer(read_only=True)
    new_application_visibility = serializers.CharField()
    admin_message = serializers.CharField(read_only=True)
    access_list = serializers.CharField(allow_blank=True)
    url = UUIDHyperlinkedIdentityField(
        view_name='api:v2:machinerequest-detail', )

    #FIXME: tags are missing here.
    # version change log is missing
    #
    class Meta:
        model = MachineRequest
        fields = (
            'id',
            'uuid',
            'url',
            'instance',
            'status',
            'old_status',
            'new_version_tags',
            'new_version_change_log',
            'admin_message',
            'new_application_name',
            'new_application_version',
            'new_application_visibility',
            'new_version_memory_min',
            'new_version_cpu_min',
            'access_list',
        )
class ImageAccessListSerializer(serializers.HyperlinkedModelSerializer):
    image = ImageRelatedField(
        source='application',
        queryset=Image.objects.none())
    match = ModelRelatedField(
        source='patternmatch',
        queryset=filter_current_user_queryset,
        serializer_class=PatternMatchSummarySerializer,
        style={'base_template': 'input.html'})
    url = serializers.HyperlinkedIdentityField(
        view_name='api:v2:applicationaccesslist-detail',
    )

    class Meta:
        model = ApplicationPatternMatch
        fields = (
            'id',
            'url',
            'image',
            'match'
        )
Exemple #8
0
class LicenseSerializer(serializers.HyperlinkedModelSerializer):
    text = serializers.CharField(source='license_text')
    type = ModelRelatedField(lookup_field='name',
                             source='license_type',
                             queryset=LicenseType.objects.all(),
                             serializer_class=LicenseTypeSummarySerializer,
                             style={'base_template': 'input.html'})
    url = UUIDHyperlinkedIdentityField(view_name='api:v2:license-detail', )
    created_by = serializers.SlugRelatedField(
        slug_field='username',
        queryset=AtmosphereUser.objects.all(),
        required=False)

    def create(self, validated_data):

        if 'created_by' not in validated_data:
            request = self.context.get('request')
            if request and request.user:
                validated_data['created_by'] = request.user
        return super(LicenseSerializer, self).create(validated_data)

    class Meta:
        model = License
        fields = ('id', 'url', 'uuid', 'created_by', 'title', 'text', 'type')
Exemple #9
0
class InstanceSerializer(serializers.HyperlinkedModelSerializer):
    identity = IdentitySummarySerializer(source='created_by_identity')
    user = UserSummarySerializer(source='created_by')
    provider = ProviderSummarySerializer(source='created_by_identity.provider')
    status = serializers.CharField(source='api_status', read_only=True)
    activity = serializers.CharField(source='api_activity', read_only=True)
    projects = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    scripts = ModelRelatedField(many=True,
                                required=False,
                                queryset=BootScript.objects.all(),
                                serializer_class=BootScriptSummarySerializer,
                                style={'base_template': 'input.html'})
    size = serializers.SerializerMethodField()
    image = serializers.SerializerMethodField()
    ip_address = serializers.SerializerMethodField()
    usage = serializers.SerializerMethodField()
    version = serializers.SerializerMethodField()
    allocation_source = serializers.SerializerMethodField()
    uuid = serializers.CharField(source='provider_alias')
    url = UUIDHyperlinkedIdentityField(view_name='api:v2:instance-detail',
                                       lookup_field='uuid',
                                       uuid_field='provider_alias')

    def get_allocation_source(self, instance):
        snapshot = InstanceAllocationSourceSnapshot.objects.filter(
            instance=instance).first()
        if not snapshot:
            return None
        serializer = AllocationSourceSerializer(snapshot.allocation_source,
                                                context=self.context)
        return serializer.data

    def get_usage(self, instance):
        return instance.get_total_hours()

    def get_size(self, obj):
        size = obj.get_size()
        serializer = SizeSummarySerializer(size, context=self.context)
        return serializer.data

    def get_image(self, obj):
        if obj.source.is_volume():
            return {}
        image_uuid = obj.application_uuid()
        image = Image.objects.get(uuid=image_uuid)
        serializer = ImageSummarySerializer(image, context=self.context)
        return serializer.data

    def get_ip_address(self, obj):
        status = obj.esh_status()
        if status in ["suspended", "shutoff", "shelved"]:
            return "0.0.0.0"
        return obj.ip_address

    def get_version(self, obj):
        if obj.source.is_volume():
            return {}
        version = obj.source.providermachine.application_version
        serializer = ImageVersionSummarySerializer(version,
                                                   context=self.context)
        return serializer.data

    class Meta:
        model = Instance
        fields = (
            'id',
            'uuid',
            'url',
            'name',
            'status',
            'activity',
            'size',
            'ip_address',
            'shell',
            'vnc',
            'web_desktop',
            'identity',
            'user',
            'provider',
            'image',
            'version',  # NOTE:Should replace image?
            'usage',
            'scripts',
            'projects',
            'start_date',
            'end_date',
            'allocation_source',
        )
Exemple #10
0
class MachineRequestSerializer(serializers.HyperlinkedModelSerializer):
    def validate(self, data):

        # set the parent machine
        parent_machine = ProviderMachine.objects.get(
            instance_source__id=data['instance'].source_id,
            instance_source__provider=data['instance'].provider)
        data['parent_machine'] = parent_machine

        # make sure user has access to the new provider
        user = data['new_machine_owner']
        provider = data['new_machine_provider']
        queryset = user.identity_set.filter(provider=provider)
        if not queryset.exists():
            raise exceptions.ValidationError(
                "User %s does not have access to provider %s." %
                (user.username, provider))

        # make sure provider has imaging enabled
        if not provider.public:
            raise exceptions.ValidationError(
                "Provider %s does not allow imaging." % (provider))

        # TODO: make sure user has access to parent machine

        return data

    uuid = serializers.CharField(read_only=True)
    identity = IdentityRelatedField(source='membership.identity',
                                    queryset=Identity.objects.none())
    instance = ModelRelatedField(queryset=Instance.objects.all(),
                                 serializer_class=InstanceSummarySerializer,
                                 style={'base_template': 'input.html'})
    status = StatusTypeRelatedField(queryset=StatusType.objects.none(),
                                    allow_null=True,
                                    required=False)
    admin_message = serializers.CharField(read_only=True)
    parent_machine = ModelRelatedField(
        required=False,
        lookup_field="uuid",
        queryset=ProviderMachine.objects.all(),
        serializer_class=ProviderMachineSummarySerializer,
        style={'base_template': 'input.html'})

    new_application_name = serializers.CharField(
        validators=[NoSpecialCharacters('!"#$%&\'*+,/;<=>?@[\\]^_`{|}~')])
    new_application_description = serializers.CharField()
    old_status = serializers.CharField(required=False)
    new_application_visibility = serializers.CharField()
    access_list = serializers.CharField(allow_blank=True)
    iplant_sys_files = serializers.CharField(allow_blank=True)
    installed_software = serializers.CharField()
    exclude_files = serializers.CharField(allow_blank=True)
    new_version_name = serializers.CharField()
    new_version_change_log = serializers.CharField()
    new_version_tags = serializers.CharField(required=False, allow_blank=True)
    new_version_memory_min = serializers.CharField()
    new_version_cpu_min = serializers.CharField()
    new_version_allow_imaging = serializers.BooleanField()
    new_version_forked = serializers.BooleanField()
    new_version_licenses = ModelRelatedField(
        many=True,
        queryset=License.objects.all(),
        serializer_class=LicenseSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_version_scripts = ModelRelatedField(
        many=True,
        queryset=BootScript.objects.all(),
        serializer_class=BootScriptSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_version_membership = ModelRelatedField(
        many=True,
        queryset=Group.objects.all(),
        serializer_class=GroupSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_machine_provider = ModelRelatedField(
        queryset=Provider.objects.all(),
        serializer_class=ProviderSummarySerializer,
        style={'base_template': 'input.html'})
    new_machine_owner = ModelRelatedField(
        queryset=User.objects.all(),
        serializer_class=UserSummarySerializer,
        style={'base_template': 'input.html'})
    start_date = serializers.DateTimeField(read_only=True)
    end_date = serializers.DateTimeField(read_only=True)
    new_machine = ModelRelatedField(
        required=False,
        queryset=ProviderMachine.objects.all(),
        serializer_class=ProviderMachineSummarySerializer,
        style={'base_template': 'input.html'})
    new_application_version = ImageVersionSummarySerializer(read_only=True)
    url = UUIDHyperlinkedIdentityField(
        view_name='api:v2:machinerequest-detail', )

    class Meta:
        model = MachineRequest
        fields = ('id', 'uuid', 'url', 'instance', 'identity', 'status',
                  'old_status', 'parent_machine', 'admin_message',
                  'new_application_name', 'new_application_description',
                  'new_application_visibility', 'access_list',
                  'iplant_sys_files', 'installed_software', 'exclude_files',
                  'new_version_name', 'new_version_change_log',
                  'new_version_tags', 'new_version_memory_min',
                  'new_version_cpu_min', 'new_version_allow_imaging',
                  'new_version_forked', 'new_version_licenses',
                  'new_version_scripts', 'new_version_membership',
                  'new_machine_provider', 'new_machine_owner', 'start_date',
                  'end_date', 'new_machine', 'new_application_version')
Exemple #11
0
class MachineRequestSerializer(serializers.HyperlinkedModelSerializer):

    uuid = serializers.CharField(read_only=True)
    identity = IdentityRelatedField(source='membership.identity',
                                    queryset=Identity.objects.none())
    # This is a *STAFF EXCLUSIVE* serializer. These are the values that make it that way:
    admin_message = serializers.CharField(read_only=True)
    parent_machine = ModelRelatedField(
        required=False,
        lookup_field="uuid",
        queryset=ProviderMachine.objects.all(),
        serializer_class=ProviderMachineSummarySerializer,
        style={'base_template': 'input.html'})

    instance = ModelRelatedField(queryset=Instance.objects.all(),
                                 serializer_class=InstanceSummarySerializer,
                                 style={'base_template': 'input.html'})
    status = StatusTypeRelatedField(queryset=StatusType.objects.none(),
                                    allow_null=True,
                                    required=False)
    old_status = serializers.CharField(required=False)

    new_application_visibility = serializers.CharField()
    new_application_version = ImageVersionSummarySerializer(read_only=True)
    new_application_name = serializers.CharField(
        validators=[NoSpecialCharacters('!"#$%&\'*+,/;<=>?@[\\]^_`{|}~')])
    new_application_description = serializers.CharField()
    access_list = serializers.CharField(allow_blank=True)
    system_files = serializers.CharField(allow_blank=True, required=False)
    installed_software = serializers.CharField()
    exclude_files = serializers.CharField(allow_blank=True)
    new_version_name = serializers.CharField()
    new_version_change_log = serializers.CharField(required=False,
                                                   allow_blank=True)
    new_version_tags = serializers.CharField(required=False, allow_blank=True)
    new_version_memory_min = serializers.CharField()
    new_version_cpu_min = serializers.CharField()
    new_version_allow_imaging = serializers.BooleanField()
    new_version_forked = serializers.BooleanField()
    new_version_licenses = ModelRelatedField(
        many=True,
        queryset=License.objects.all(),
        serializer_class=LicenseSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_version_scripts = ModelRelatedField(
        many=True,
        queryset=BootScript.objects.all(),
        serializer_class=BootScriptSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_version_membership = ModelRelatedField(
        many=True,
        queryset=Group.objects.all(),
        serializer_class=GroupSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_machine_provider = ModelRelatedField(
        queryset=Provider.objects.all(),
        serializer_class=ProviderSummarySerializer,
        style={'base_template': 'input.html'})
    new_machine_owner = ModelRelatedField(
        queryset=User.objects.all(),
        serializer_class=UserSummarySerializer,
        style={'base_template': 'input.html'})
    start_date = serializers.DateTimeField(read_only=True)
    end_date = serializers.DateTimeField(read_only=True)
    new_machine = ModelRelatedField(
        required=False,
        queryset=ProviderMachine.objects.all(),
        serializer_class=ProviderMachineSummarySerializer,
        style={'base_template': 'input.html'})
    url = UUIDHyperlinkedIdentityField(
        view_name='api:v2:machinerequest-detail', )

    class Meta:
        model = MachineRequest
        fields = ('id', 'uuid', 'url', 'instance', 'identity', 'status',
                  'old_status', 'parent_machine', 'admin_message',
                  'new_application_name', 'new_application_description',
                  'new_application_visibility', 'access_list', 'system_files',
                  'installed_software', 'exclude_files', 'new_version_name',
                  'new_version_change_log', 'new_version_tags',
                  'new_version_memory_min', 'new_version_cpu_min',
                  'new_version_allow_imaging', 'new_version_forked',
                  'new_version_licenses', 'new_version_scripts',
                  'new_version_membership', 'new_machine_provider',
                  'new_machine_owner', 'start_date', 'end_date', 'new_machine',
                  'new_application_version')
Exemple #12
0
class UserMachineRequestSerializer(serializers.HyperlinkedModelSerializer):

    uuid = serializers.CharField(read_only=True)
    admin_message = serializers.CharField(read_only=True)
    instance = ModelRelatedField(queryset=Instance.objects.all(),
                                 serializer_class=InstanceSummarySerializer,
                                 style={'base_template': 'input.html'})
    start_date = serializers.DateTimeField(read_only=True)
    end_date = serializers.DateTimeField(read_only=True)
    status = StatusTypeRelatedField(queryset=StatusType.objects.none(),
                                    allow_null=True,
                                    required=False)
    old_status = serializers.CharField(source='clean_old_status',
                                       required=False)

    new_application_visibility = serializers.CharField()
    new_application_version = ImageVersionSummarySerializer(read_only=True)
    new_application_name = serializers.CharField(
        validators=[NoSpecialCharacters('!"#$%&\'*+,/;<=>?@[\\]^`{|}~')])
    new_application_description = serializers.CharField()
    access_list = serializers.CharField(allow_blank=True)
    system_files = serializers.CharField(allow_blank=True, required=False)
    installed_software = serializers.CharField()
    exclude_files = serializers.CharField(allow_blank=True)
    new_version_name = serializers.CharField()
    new_version_change_log = serializers.CharField(required=False,
                                                   allow_blank=True)
    new_version_tags = serializers.CharField(required=False, allow_blank=True)
    new_version_memory_min = serializers.CharField()
    new_version_cpu_min = serializers.CharField()
    new_version_allow_imaging = serializers.BooleanField()
    new_version_forked = serializers.BooleanField()
    new_version_licenses = ModelRelatedField(
        many=True,
        queryset=License.objects.all(),
        serializer_class=LicenseSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_version_scripts = ModelRelatedField(
        many=True,
        queryset=BootScript.objects.all(),
        serializer_class=BootScriptSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_version_membership = ModelRelatedField(
        many=True,
        queryset=Group.objects.all(),
        serializer_class=GroupSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_machine_provider = ModelRelatedField(
        queryset=Provider.objects.all(),
        serializer_class=ProviderSummarySerializer,
        style={'base_template': 'input.html'},
        required=False)
    new_machine = ModelRelatedField(
        required=False,
        queryset=ProviderMachine.objects.all(),
        serializer_class=ProviderMachineSummarySerializer,
        style={'base_template': 'input.html'})
    # Absent: new_machine_owner -- determined by User submission
    url = UUIDHyperlinkedIdentityField(
        view_name='api:v2:machinerequest-detail', )

    #FIXME: tags are missing here.
    # version change log is missing
    #
    class Meta:
        model = MachineRequest
        fields = (
            'id',
            'uuid',
            'url',
            'start_date',
            'end_date',
            'admin_message',
            'instance',
            'status',
            'old_status',
            'new_application_visibility',
            'new_application_name',
            'new_application_description',
            'access_list',
            'system_files',
            'installed_software',
            'exclude_files',
            'new_version_name',
            'new_version_change_log',
            'new_version_tags',
            'new_version_memory_min',
            'new_version_cpu_min',
            'new_version_allow_imaging',
            'new_version_forked',
            'new_version_licenses',
            'new_version_scripts',
            'new_version_membership',
            'new_machine_provider',
            'new_application_version',
            'new_machine',
        )
Exemple #13
0
class ImageVersionSerializer(serializers.HyperlinkedModelSerializer):
    """
    Serializer for ApplicationVersion (aka 'image_version')
    """
    # NOTE: Implicitly included via 'fields'
    # id, application
    parent = ImageVersionSummarySerializer()
    # name, change_log, allow_imaging
    licenses = ModelRelatedField(many=True,
                                 queryset=License.objects.all(),
                                 serializer_class=LicenseSummarySerializer,
                                 style={'base_template': 'input.html'})
    scripts = ModelRelatedField(source='boot_scripts',
                                many=True,
                                queryset=BootScript.objects.all(),
                                serializer_class=BootScriptSummarySerializer,
                                style={'base_template': 'input.html'})
    membership = serializers.SlugRelatedField(slug_field='name',
                                              read_only=True,
                                              many=True)  # NEW
    user = UserSummarySerializer(source='created_by')
    identity = IdentitySummarySerializer(source='created_by_identity')
    machines = ModelRelatedField(
        many=True,
        queryset=ProviderMachine.objects.all(),
        serializer_class=ProviderMachineSummarySerializer,
        style={'base_template': 'input.html'})
    image = ModelRelatedField(source='application',
                              queryset=Image.objects.all(),
                              serializer_class=ImageSummarySerializer,
                              style={'base_template': 'input.html'})
    start_date = serializers.DateTimeField()
    min_mem = serializers.IntegerField(source='threshold.memory_min')
    min_cpu = serializers.IntegerField(source='threshold.cpu_min')
    end_date = serializers.DateTimeField(allow_null=True)
    url = UUIDHyperlinkedIdentityField(view_name='api:v2:imageversion-detail',
                                       uuid_field='id')

    class Meta:
        model = ImageVersion
        fields = ('id', 'url', 'parent', 'name', 'change_log', 'image',
                  'machines', 'allow_imaging', 'licenses', 'membership',
                  'min_mem', 'min_cpu', 'scripts', 'user', 'identity',
                  'start_date', 'end_date')

    def update(self, instance, validated_data):
        if 'min_cpu' in self.initial_data or 'min_mem' in self.initial_data:
            self.update_threshold(instance, validated_data)
        return super(ImageVersionSerializer,
                     self).update(instance, validated_data)

    def validate_min_cpu(self, value):
        if value < 0 or value > 16:
            raise serializers.ValidationError(
                "Value of CPU must be between 1 & 16")
        return value

    def validate_min_mem(self, value):
        if value < 0 or value > 32 * 1024:
            raise serializers.ValidationError(
                "Value of mem must be between 1 & 32 GB")
        return value

    def update_threshold(self, instance, validated_data):
        current_threshold = instance.get_threshold()

        try:
            current_mem_min = current_threshold.memory_min
        except:
            current_mem_min = 0

        try:
            current_cpu_min = current_threshold.cpu_min
        except:
            current_cpu_min = 0

        try:
            new_mem_min = validated_data.get('threshold')['memory_min']
        except:
            new_mem_min = current_mem_min

        try:
            new_cpu_min = validated_data.get('threshold')['cpu_min']
        except:
            new_cpu_min = current_cpu_min

        if not current_threshold:
            new_threshold = ApplicationThreshold.objects.create(
                application_version=instance,
                memory_min=new_mem_min,
                cpu_min=new_cpu_min)
        else:
            new_threshold = ApplicationThreshold.objects.get(
                application_version=instance)
            new_threshold.memory_min = new_mem_min
            new_threshold.cpu_min = new_cpu_min
            new_threshold.save()

        validated_data['threshold'] = new_threshold
Exemple #14
0
class ProjectSerializer(serializers.HyperlinkedModelSerializer):
    images = ImageSummarySerializer(source='applications',
                                    many=True,
                                    read_only=True)
    instances = InstanceSummarySerializer(source='active_instances',
                                          many=True,
                                          read_only=True)
    links = ExternalLinkSummarySerializer(many=True, read_only=True)
    volumes = VolumeSummarySerializer(source='active_volumes',
                                      many=True,
                                      read_only=True)
    # note: both of these requests become a single DB query, but I'm choosing
    # the owner.name route so the API doesn't break when we start adding users
    # to groups owner = UserSerializer(source='owner.user_set.first')
    created_by = ModelRelatedField(lookup_field="username",
                                   default=serializers.CurrentUserDefault(),
                                   queryset=AtmosphereUser.objects.all(),
                                   serializer_class=UserSummarySerializer,
                                   style={'base_template': 'input.html'})
    owner = ModelRelatedField(lookup_field="name",
                              queryset=Group.objects.all(),
                              serializer_class=GroupSummarySerializer,
                              style={'base_template': 'input.html'})
    url = UUIDHyperlinkedIdentityField(view_name='api:v2:project-detail', )
    users = UserSummarySerializer(source='get_users',
                                  many=True,
                                  read_only=True)
    leaders = UserSummarySerializer(source='get_leaders',
                                    many=True,
                                    read_only=True)

    def update(self, instance, validated_data):
        """
        Check that project does not have shared resources.
        If so, do not allow owner changes.
        """
        new_owner = validated_data.get('owner')
        current_owner = instance.owner
        if new_owner and current_owner != new_owner:
            self.validate_ownership(instance, current_owner)
        return super(ProjectSerializer, self).update(instance, validated_data)

    def validate_ownership(self, project, current_owner):
        if project.has_shared_resources():
            raise ValidationError(
                "Cannot update ownership for a project when it contains "
                "shared cloud resources. To update project ownership, "
                "all shared cloud resources must be "
                "moved to another project or deleted")
        request = self.context.get('request')
        if not request:
            return True
        request_user = request.user
        if request_user not in project.get_leaders():
            raise ValidationError("This project has been shared with you. "
                                  "To change a projects ownership, "
                                  "you must be the project owner.")
        return True

    class Meta:
        model = Project
        fields = ('id', 'uuid', 'url', 'name', 'description', 'created_by',
                  'owner', 'users', 'leaders', 'instances', 'images', 'links',
                  'volumes', 'start_date', 'end_date')