Updated syndicate admin and models:
[plstackapi.git] / planetstack / syndicate_storage / admin.py
1 from django.contrib import admin
2
3 from syndicate_storage.models import *
4 from django import forms
5 from django.utils.safestring import mark_safe
6 from django.contrib.auth.admin import UserAdmin
7 from django.contrib.admin.widgets import FilteredSelectMultiple
8 from django.contrib.auth.forms import ReadOnlyPasswordHashField
9 from django.contrib.auth.signals import user_logged_in
10 from django.utils import timezone
11 from django.contrib.contenttypes import generic
12 from suit.widgets import LinkedSelect
13 from core.admin import ReadOnlyTabularInline,ReadOnlyAwareAdmin,SingletonAdmin,SliceInline,ServiceAttrAsTabInline,PlanetStackBaseAdmin, PlStackTabularInline,SliceROInline,ServiceAttrAsTabROInline
14 from suit.widgets import LinkedSelect
15 from django.core.exceptions import ValidationError, ObjectDoesNotExist
16
17 class SyndicateServiceAdmin(SingletonAdmin,ReadOnlyAwareAdmin):
18     model = SyndicateService
19     verbose_name = "Syndicate Storage"
20     verbose_name_plural = "Syndicate Storage"
21     list_display = ("name","enabled")
22     fieldsets = [(None, {'fields': ['name','enabled','versionNumber', 'description',], 'classes':['suit-tab suit-tab-general']})]
23     inlines = [SliceInline,ServiceAttrAsTabInline]
24
25     user_readonly_fields = ['name','enabled','versionNumber','description']
26     user_readonly_inlines = [SliceROInline, ServiceAttrAsTabROInline]
27
28     suit_form_tabs =(('general', 'Syndicate Storage Details'),
29         ('slices','Slices'),
30         ('serviceattrs','Additional Attributes'),
31     )
32
33
34 class VolumeAccessRightForUserROInline(ReadOnlyTabularInline):
35     model = VolumeAccessRight
36     extra = 0
37     suit_classes = 'suit-tab suit-tab-volumeAccessRights'
38     fields = ['volume','cap_read_data', 'cap_write_data', 'cap_host_data']
39
40 class VolumeAccessRightROInline(ReadOnlyTabularInline):
41     model = VolumeAccessRight
42     extra = 0
43     suit_classes = 'suit-tab suit-tab-volumeAccessRights'
44     fields = ['owner_id','cap_read_data', 'cap_write_data', 'cap_host_data']
45
46 class VolumeAccessRightInline(PlStackTabularInline):
47     model = VolumeAccessRight
48     extra = 0
49     suit_classes = 'suit-tab suit-tab-volumeAccessRights'
50
51
52 class VolumeSliceFormSet( forms.models.BaseInlineFormSet ):
53     # verify that our VolumeSlice is valid
54
55     @classmethod
56     def verify_unchanged( cls, volume_pk, slice_pk, field_name, new_value ):
57         vs = None
58         try:
59            vs = VolumeSlice.objects.get( volume_id=volume_pk, slice_id=slice_pk )
60         except ObjectDoesNotExist, dne:
61            return True, None
62
63         old_value = getattr( vs, field_name )
64         if old_value != new_value:
65             return False, old_value
66         else:
67             return True, None
68
69
70     def clean( self ):
71         for form in self.forms:
72             # check each inline's cleaned data, if it's valid
73             cleaned_data = None
74             try:
75                 if form.cleaned_data:
76                     cleaned_data = form.cleaned_data
77             except AttributeError:
78                 continue
79              
80             # verify that the ports haven't changed 
81             volume_pk = cleaned_data['volume_id'].pk
82             slice_pk = cleaned_data['slice_id'].pk
83            
84             if not cleaned_data.has_key('UG_portnum'):
85                 raise ValidationError("Missing UG port number")
86
87             if not cleaned_data.has_key('RG_portnum'):
88                 raise ValidationError("Missing RG port number")
89
90             rc1, old_peer_port = VolumeSliceFormSet.verify_unchanged( volume_pk, slice_pk, 'UG_portnum', cleaned_data['UG_portnum'] )
91             rc2, old_replicate_port = VolumeSliceFormSet.verify_unchanged( volume_pk, slice_pk, 'RG_portnum', cleaned_data['RG_portnum'] )
92
93             err1str = ""
94             err2str = ""
95             if not rc1:
96                 err1str = "change %s back to %s" % (cleaned_data['UG_portnum'], old_peer_port)
97             if not rc2:
98                 err2str = " and change %s back to %s" % (cleaned_data['RG_portnum'], old_replicate_port )
99
100             if not rc1 or not rc2:
101                 raise ValidationError("At this time, port numbers cannot be changed once they are set. Please %s %s" % (err1str, err2str))
102             
103             
104
105 class VolumeSliceInline(PlStackTabularInline):
106     model = VolumeSlice
107     extra = 0
108     suit_classes = 'suit-tab suit-tab-volumeSlices'
109     fields = ['volume_id', 'slice_id', 'cap_read_data', 'cap_write_data', 'cap_host_data', 'UG_portnum', 'RG_portnum']
110
111     formset = VolumeSliceFormSet
112     
113     readonly_fields = ['credentials_blob']
114  
115
116 class VolumeSliceROInline(ReadOnlyTabularInline):
117     model = VolumeSlice
118     extra = 0
119     suit_classes = 'suit-tab suit-tab-volumeSlices'
120     fields = ['volume_id', 'slice_id', 'cap_read_data', 'cap_write_data', 'cap_host_data', 'UG_portnum', 'RG_portnum']
121
122     formset = VolumeSliceFormSet
123
124     readonly_fields = ['credentials_blob']
125     
126
127 class VolumeAdmin(ReadOnlyAwareAdmin):
128     model = Volume
129    
130     def get_readonly_fields(self, request, obj=None ):
131        always_readonly = []
132        if obj == None:
133           # all fields are editable on add
134           return always_readonly
135
136        else:
137           # can't change owner, slice id, or block size on update
138           return ['blocksize', 'owner_id'] + always_readonly
139
140
141     list_display = ['name', 'owner_id']
142
143     detailsFieldList = ['name', 'owner_id', 'description','blocksize', 'private','archive', 'cap_read_data', 'cap_write_data', 'cap_host_data' ]
144
145     fieldsets = [
146         (None, {'fields': detailsFieldList, 'classes':['suit-tab suit-tab-general']}),
147     ]
148
149     inlines = [VolumeAccessRightInline, VolumeSliceInline]
150
151     user_readonly_fields = ['name','owner_id','description','blocksize','private', 'archive', 'cap_read_data', 'cap_write_data', 'cap_host_data']
152     
153     user_readonly_inlines = [VolumeAccessRightROInline, VolumeSliceROInline]
154
155     suit_form_tabs =(('general', 'Volume Details'),
156                      ('volumeSlices', 'Slices'),
157                      ('volumeAccessRights', 'Volume Access Rights'))
158     
159     def queryset(self, request):
160        # only show volumes that are public, or owned by the caller 
161        return Volume.select_by_user(request.user)
162     
163     
164 # left panel:
165 admin.site.register(SyndicateService, SyndicateServiceAdmin)
166 admin.site.register(Volume, VolumeAdmin)