Merge lp:~rvb/maas/ipfield into lp:~maas-committers/maas/trunk
- ipfield
- Merge into trunk
Proposed by
Raphaël Badin
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Raphaël Badin | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 2525 | ||||
Proposed branch: | lp:~rvb/maas/ipfield | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Diff against target: |
694 lines (+445/-29) 8 files modified
src/maasserver/fields.py (+27/-0) src/maasserver/migrations/0088_ip_to_custom_field.py (+377/-0) src/maasserver/models/dhcplease.py (+5/-3) src/maasserver/models/network.py (+3/-3) src/maasserver/models/nodegroupinterface.py (+11/-11) src/maasserver/models/staticipaddress.py (+3/-12) src/maasserver/tests/models.py (+6/-0) src/maasserver/tests/test_fields.py (+13/-0) |
||||
To merge this branch: | bzr merge lp:~rvb/maas/ipfield | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email:
|
Commit message
Re-do the fix for bug 1338452 in a more consistent way: work around the Django bug (see reference in the code) by defining a custom IP field. Update all the IP fields in the codebase to use the new field.
Description of the change
Although this is a bit of a hack, it's much safer than having a workaround in just one place of the code.
I've tested that an upgrade to the package built from this branch works fine (objects with IP address fields look okay) and I ran a test in the lab with this branch.
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Gavin Panella (allenap) : | # |
review:
Approve
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Julian Edwards (julian-edwards) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Raphaël Badin (rvb) wrote : | # |
On 07/08/2014 03:12 AM, Julian Edwards wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Please let's not have a repeat of the TestCase debacle, and call this
> *MAAS*IPAddress
Fair point. Done.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/maasserver/fields.py' | |||
2 | --- src/maasserver/fields.py 2014-05-19 14:44:58 +0000 | |||
3 | +++ src/maasserver/fields.py 2014-07-08 07:55:43 +0000 | |||
4 | @@ -14,6 +14,7 @@ | |||
5 | 14 | __metaclass__ = type | 14 | __metaclass__ = type |
6 | 15 | __all__ = [ | 15 | __all__ = [ |
7 | 16 | "EditableBinaryField", | 16 | "EditableBinaryField", |
8 | 17 | "MAASIPAddressField", | ||
9 | 17 | "MAC", | 18 | "MAC", |
10 | 18 | "MACAddressField", | 19 | "MACAddressField", |
11 | 19 | "MACAddressFormField", | 20 | "MACAddressFormField", |
12 | @@ -33,6 +34,7 @@ | |||
13 | 33 | from django.db.models import ( | 34 | from django.db.models import ( |
14 | 34 | BinaryField, | 35 | BinaryField, |
15 | 35 | Field, | 36 | Field, |
16 | 37 | GenericIPAddressField, | ||
17 | 36 | SubfieldBase, | 38 | SubfieldBase, |
18 | 37 | ) | 39 | ) |
19 | 38 | from django.forms import ( | 40 | from django.forms import ( |
20 | @@ -90,6 +92,7 @@ | |||
21 | 90 | "^maasserver\.fields\.JSONObjectField", | 92 | "^maasserver\.fields\.JSONObjectField", |
22 | 91 | "^maasserver\.fields\.XMLField", | 93 | "^maasserver\.fields\.XMLField", |
23 | 92 | "^maasserver\.fields\.EditableBinaryField", | 94 | "^maasserver\.fields\.EditableBinaryField", |
24 | 95 | "^maasserver\.fields\.MAASIPAddressField", | ||
25 | 93 | ]) | 96 | ]) |
26 | 94 | 97 | ||
27 | 95 | 98 | ||
28 | @@ -385,3 +388,27 @@ | |||
29 | 385 | def __init__(self, *args, **kwargs): | 388 | def __init__(self, *args, **kwargs): |
30 | 386 | super(EditableBinaryField, self).__init__(*args, **kwargs) | 389 | super(EditableBinaryField, self).__init__(*args, **kwargs) |
31 | 387 | self.editable = True | 390 | self.editable = True |
32 | 391 | |||
33 | 392 | |||
34 | 393 | class MAASIPAddressField(GenericIPAddressField): | ||
35 | 394 | """A version of GenericIPAddressField with a custom get_internal_type(). | ||
36 | 395 | |||
37 | 396 | This class exists to work around a bug in Django that inserts a HOST() cast | ||
38 | 397 | on the IP, causing the wrong comparison on the IP field. See | ||
39 | 398 | https://code.djangoproject.com/ticket/11442 for details. | ||
40 | 399 | """ | ||
41 | 400 | |||
42 | 401 | def get_internal_type(self): | ||
43 | 402 | """Returns a value different from 'GenericIPAddressField' and | ||
44 | 403 | 'IPAddressField' to force Django not to use a HOST() case when | ||
45 | 404 | performing operation on this field. | ||
46 | 405 | """ | ||
47 | 406 | return "IPField" | ||
48 | 407 | |||
49 | 408 | def db_type(self, connection): | ||
50 | 409 | """Returns the database column data type for IPAddressField. | ||
51 | 410 | |||
52 | 411 | Override the default implementation which uses get_internal_type() | ||
53 | 412 | and force a 'inet' type field. | ||
54 | 413 | """ | ||
55 | 414 | return 'inet' | ||
56 | 388 | 415 | ||
57 | === added file 'src/maasserver/migrations/0088_ip_to_custom_field.py' | |||
58 | --- src/maasserver/migrations/0088_ip_to_custom_field.py 1970-01-01 00:00:00 +0000 | |||
59 | +++ src/maasserver/migrations/0088_ip_to_custom_field.py 2014-07-08 07:55:43 +0000 | |||
60 | @@ -0,0 +1,377 @@ | |||
61 | 1 | from django.db import models | ||
62 | 2 | from south.db import db | ||
63 | 3 | # -*- coding: utf-8 -*- | ||
64 | 4 | from south.utils import datetime_utils as datetime | ||
65 | 5 | from south.v2 import SchemaMigration | ||
66 | 6 | |||
67 | 7 | |||
68 | 8 | class Migration(SchemaMigration): | ||
69 | 9 | |||
70 | 10 | def forwards(self, orm): | ||
71 | 11 | |||
72 | 12 | # Changing field 'NodeGroupInterface.ip_range_high' | ||
73 | 13 | db.alter_column(u'maasserver_nodegroupinterface', 'ip_range_high', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
74 | 14 | |||
75 | 15 | # Changing field 'NodeGroupInterface.static_ip_range_low' | ||
76 | 16 | db.alter_column(u'maasserver_nodegroupinterface', 'static_ip_range_low', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
77 | 17 | |||
78 | 18 | # Changing field 'NodeGroupInterface.ip' | ||
79 | 19 | db.alter_column(u'maasserver_nodegroupinterface', 'ip', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39)) | ||
80 | 20 | |||
81 | 21 | # Changing field 'NodeGroupInterface.ip_range_low' | ||
82 | 22 | db.alter_column(u'maasserver_nodegroupinterface', 'ip_range_low', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
83 | 23 | |||
84 | 24 | # Changing field 'NodeGroupInterface.subnet_mask' | ||
85 | 25 | db.alter_column(u'maasserver_nodegroupinterface', 'subnet_mask', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
86 | 26 | |||
87 | 27 | # Changing field 'NodeGroupInterface.broadcast_ip' | ||
88 | 28 | db.alter_column(u'maasserver_nodegroupinterface', 'broadcast_ip', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
89 | 29 | |||
90 | 30 | # Changing field 'NodeGroupInterface.router_ip' | ||
91 | 31 | db.alter_column(u'maasserver_nodegroupinterface', 'router_ip', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
92 | 32 | |||
93 | 33 | # Changing field 'NodeGroupInterface.foreign_dhcp_ip' | ||
94 | 34 | db.alter_column(u'maasserver_nodegroupinterface', 'foreign_dhcp_ip', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
95 | 35 | |||
96 | 36 | # Changing field 'NodeGroupInterface.static_ip_range_high' | ||
97 | 37 | db.alter_column(u'maasserver_nodegroupinterface', 'static_ip_range_high', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True)) | ||
98 | 38 | |||
99 | 39 | # Changing field 'StaticIPAddress.ip' | ||
100 | 40 | db.alter_column(u'maasserver_staticipaddress', 'ip', self.gf('maasserver.fields.MAASIPAddressField')(unique=True, max_length=39)) | ||
101 | 41 | |||
102 | 42 | # Changing field 'DHCPLease.ip' | ||
103 | 43 | db.alter_column(u'maasserver_dhcplease', 'ip', self.gf('maasserver.fields.MAASIPAddressField')(unique=True, max_length=39)) | ||
104 | 44 | |||
105 | 45 | # Changing field 'Network.ip' | ||
106 | 46 | db.alter_column(u'maasserver_network', 'ip', self.gf('maasserver.fields.MAASIPAddressField')(unique=True, max_length=39)) | ||
107 | 47 | |||
108 | 48 | # Changing field 'Network.netmask' | ||
109 | 49 | db.alter_column(u'maasserver_network', 'netmask', self.gf('maasserver.fields.MAASIPAddressField')(max_length=39)) | ||
110 | 50 | |||
111 | 51 | def backwards(self, orm): | ||
112 | 52 | |||
113 | 53 | # Changing field 'NodeGroupInterface.ip_range_high' | ||
114 | 54 | db.alter_column(u'maasserver_nodegroupinterface', 'ip_range_high', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
115 | 55 | |||
116 | 56 | # Changing field 'NodeGroupInterface.static_ip_range_low' | ||
117 | 57 | db.alter_column(u'maasserver_nodegroupinterface', 'static_ip_range_low', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
118 | 58 | |||
119 | 59 | # Changing field 'NodeGroupInterface.ip' | ||
120 | 60 | db.alter_column(u'maasserver_nodegroupinterface', 'ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39)) | ||
121 | 61 | |||
122 | 62 | # Changing field 'NodeGroupInterface.ip_range_low' | ||
123 | 63 | db.alter_column(u'maasserver_nodegroupinterface', 'ip_range_low', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
124 | 64 | |||
125 | 65 | # Changing field 'NodeGroupInterface.subnet_mask' | ||
126 | 66 | db.alter_column(u'maasserver_nodegroupinterface', 'subnet_mask', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
127 | 67 | |||
128 | 68 | # Changing field 'NodeGroupInterface.broadcast_ip' | ||
129 | 69 | db.alter_column(u'maasserver_nodegroupinterface', 'broadcast_ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
130 | 70 | |||
131 | 71 | # Changing field 'NodeGroupInterface.router_ip' | ||
132 | 72 | db.alter_column(u'maasserver_nodegroupinterface', 'router_ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
133 | 73 | |||
134 | 74 | # Changing field 'NodeGroupInterface.foreign_dhcp_ip' | ||
135 | 75 | db.alter_column(u'maasserver_nodegroupinterface', 'foreign_dhcp_ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
136 | 76 | |||
137 | 77 | # Changing field 'NodeGroupInterface.static_ip_range_high' | ||
138 | 78 | db.alter_column(u'maasserver_nodegroupinterface', 'static_ip_range_high', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True)) | ||
139 | 79 | |||
140 | 80 | # Changing field 'StaticIPAddress.ip' | ||
141 | 81 | db.alter_column(u'maasserver_staticipaddress', 'ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, unique=True)) | ||
142 | 82 | |||
143 | 83 | # Changing field 'DHCPLease.ip' | ||
144 | 84 | db.alter_column(u'maasserver_dhcplease', 'ip', self.gf('django.db.models.fields.IPAddressField')(max_length=15, unique=True)) | ||
145 | 85 | |||
146 | 86 | # Changing field 'Network.ip' | ||
147 | 87 | db.alter_column(u'maasserver_network', 'ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, unique=True)) | ||
148 | 88 | |||
149 | 89 | # Changing field 'Network.netmask' | ||
150 | 90 | db.alter_column(u'maasserver_network', 'netmask', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39)) | ||
151 | 91 | |||
152 | 92 | models = { | ||
153 | 93 | u'auth.group': { | ||
154 | 94 | 'Meta': {'object_name': 'Group'}, | ||
155 | 95 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
156 | 96 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
157 | 97 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
158 | 98 | }, | ||
159 | 99 | u'auth.permission': { | ||
160 | 100 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
161 | 101 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
162 | 102 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
163 | 103 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
164 | 104 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
165 | 105 | }, | ||
166 | 106 | u'auth.user': { | ||
167 | 107 | 'Meta': {'object_name': 'User'}, | ||
168 | 108 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
169 | 109 | 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
170 | 110 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
171 | 111 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
172 | 112 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
173 | 113 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
174 | 114 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
175 | 115 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
176 | 116 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
177 | 117 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
178 | 118 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
179 | 119 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
180 | 120 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | ||
181 | 121 | }, | ||
182 | 122 | u'contenttypes.contenttype': { | ||
183 | 123 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
184 | 124 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
185 | 125 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
186 | 126 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
187 | 127 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
188 | 128 | }, | ||
189 | 129 | u'maasserver.bootimage': { | ||
190 | 130 | 'Meta': {'unique_together': "((u'nodegroup', u'osystem', u'architecture', u'subarchitecture', u'release', u'purpose', u'label'),)", 'object_name': 'BootImage'}, | ||
191 | 131 | 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
192 | 132 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
193 | 133 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
194 | 134 | 'label': ('django.db.models.fields.CharField', [], {'default': "u'release'", 'max_length': '255'}), | ||
195 | 135 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
196 | 136 | 'osystem': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
197 | 137 | 'purpose': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
198 | 138 | 'release': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
199 | 139 | 'subarchitecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
200 | 140 | 'supported_subarches': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), | ||
201 | 141 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
202 | 142 | 'xinstall_path': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
203 | 143 | 'xinstall_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '30', 'null': 'True', 'blank': 'True'}) | ||
204 | 144 | }, | ||
205 | 145 | u'maasserver.bootsource': { | ||
206 | 146 | 'Meta': {'object_name': 'BootSource'}, | ||
207 | 147 | 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}), | ||
208 | 148 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
209 | 149 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
210 | 150 | 'keyring_data': ('maasserver.fields.EditableBinaryField', [], {'blank': 'True'}), | ||
211 | 151 | 'keyring_filename': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}), | ||
212 | 152 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
213 | 153 | 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) | ||
214 | 154 | }, | ||
215 | 155 | u'maasserver.bootsourceselection': { | ||
216 | 156 | 'Meta': {'object_name': 'BootSourceSelection'}, | ||
217 | 157 | 'arches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
218 | 158 | 'boot_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.BootSource']"}), | ||
219 | 159 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
220 | 160 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
221 | 161 | 'labels': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
222 | 162 | 'release': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
223 | 163 | 'subarches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
224 | 164 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
225 | 165 | }, | ||
226 | 166 | u'maasserver.componenterror': { | ||
227 | 167 | 'Meta': {'object_name': 'ComponentError'}, | ||
228 | 168 | 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}), | ||
229 | 169 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
230 | 170 | 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}), | ||
231 | 171 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
232 | 172 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
233 | 173 | }, | ||
234 | 174 | u'maasserver.config': { | ||
235 | 175 | 'Meta': {'object_name': 'Config'}, | ||
236 | 176 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
237 | 177 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
238 | 178 | 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'}) | ||
239 | 179 | }, | ||
240 | 180 | u'maasserver.dhcplease': { | ||
241 | 181 | 'Meta': {'object_name': 'DHCPLease'}, | ||
242 | 182 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
243 | 183 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
244 | 184 | 'mac': ('maasserver.fields.MACAddressField', [], {}), | ||
245 | 185 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}) | ||
246 | 186 | }, | ||
247 | 187 | u'maasserver.downloadprogress': { | ||
248 | 188 | 'Meta': {'object_name': 'DownloadProgress'}, | ||
249 | 189 | 'bytes_downloaded': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), | ||
250 | 190 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
251 | 191 | 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}), | ||
252 | 192 | 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
253 | 193 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
254 | 194 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
255 | 195 | 'size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), | ||
256 | 196 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
257 | 197 | }, | ||
258 | 198 | u'maasserver.filestorage': { | ||
259 | 199 | 'Meta': {'unique_together': "((u'filename', u'owner'),)", 'object_name': 'FileStorage'}, | ||
260 | 200 | 'content': ('metadataserver.fields.BinaryField', [], {'blank': 'True'}), | ||
261 | 201 | 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
262 | 202 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
263 | 203 | 'key': ('django.db.models.fields.CharField', [], {'default': "u'1ed17c44-0672-11e4-aedf-9c4e363b1c94'", 'unique': 'True', 'max_length': '36'}), | ||
264 | 204 | 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) | ||
265 | 205 | }, | ||
266 | 206 | u'maasserver.licensekey': { | ||
267 | 207 | 'Meta': {'unique_together': "((u'osystem', u'distro_series'),)", 'object_name': 'LicenseKey'}, | ||
268 | 208 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
269 | 209 | 'distro_series': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
270 | 210 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
271 | 211 | 'license_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
272 | 212 | 'osystem': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
273 | 213 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
274 | 214 | }, | ||
275 | 215 | u'maasserver.macaddress': { | ||
276 | 216 | 'Meta': {'object_name': 'MACAddress'}, | ||
277 | 217 | 'cluster_interface': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['maasserver.NodeGroupInterface']", 'null': 'True', 'blank': 'True'}), | ||
278 | 218 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
279 | 219 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
280 | 220 | 'ip_addresses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.StaticIPAddress']", 'symmetrical': 'False', 'through': u"orm['maasserver.MACStaticIPAddressLink']", 'blank': 'True'}), | ||
281 | 221 | 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}), | ||
282 | 222 | 'networks': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Network']", 'symmetrical': 'False', 'blank': 'True'}), | ||
283 | 223 | 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}), | ||
284 | 224 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
285 | 225 | }, | ||
286 | 226 | u'maasserver.macstaticipaddresslink': { | ||
287 | 227 | 'Meta': {'unique_together': "((u'ip_address', u'mac_address'),)", 'object_name': 'MACStaticIPAddressLink'}, | ||
288 | 228 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
289 | 229 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
290 | 230 | 'ip_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.StaticIPAddress']", 'unique': 'True'}), | ||
291 | 231 | 'mac_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.MACAddress']"}), | ||
292 | 232 | 'nic_alias': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), | ||
293 | 233 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
294 | 234 | }, | ||
295 | 235 | u'maasserver.network': { | ||
296 | 236 | 'Meta': {'object_name': 'Network'}, | ||
297 | 237 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
298 | 238 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
299 | 239 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
300 | 240 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), | ||
301 | 241 | 'netmask': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39'}), | ||
302 | 242 | 'vlan_tag': ('django.db.models.fields.PositiveSmallIntegerField', [], {'unique': 'True', 'null': 'True', 'blank': 'True'}) | ||
303 | 243 | }, | ||
304 | 244 | u'maasserver.node': { | ||
305 | 245 | 'Meta': {'object_name': 'Node'}, | ||
306 | 246 | 'agent_name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
307 | 247 | 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '31'}), | ||
308 | 248 | 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
309 | 249 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
310 | 250 | 'distro_series': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
311 | 251 | 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
312 | 252 | 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'unique': 'True', 'max_length': '255', 'blank': 'True'}), | ||
313 | 253 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
314 | 254 | 'license_key': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), | ||
315 | 255 | 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
316 | 256 | 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
317 | 257 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}), | ||
318 | 258 | 'osystem': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
319 | 259 | 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), | ||
320 | 260 | 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}), | ||
321 | 261 | 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}), | ||
322 | 262 | 'routers': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'macaddr'", 'null': 'True', 'blank': 'True'}), | ||
323 | 263 | 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}), | ||
324 | 264 | 'storage': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
325 | 265 | 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-1ececdb4-0672-11e4-aedf-9c4e363b1c94'", 'unique': 'True', 'max_length': '41'}), | ||
326 | 266 | 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}), | ||
327 | 267 | 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'null': 'True'}), | ||
328 | 268 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
329 | 269 | 'zone': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Zone']", 'on_delete': 'models.SET_DEFAULT'}) | ||
330 | 270 | }, | ||
331 | 271 | u'maasserver.nodegroup': { | ||
332 | 272 | 'Meta': {'object_name': 'NodeGroup'}, | ||
333 | 273 | 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}), | ||
334 | 274 | 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'unique': 'True'}), | ||
335 | 275 | 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}), | ||
336 | 276 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
337 | 277 | 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
338 | 278 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
339 | 279 | 'maas_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
340 | 280 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}), | ||
341 | 281 | 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
342 | 282 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
343 | 283 | 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}) | ||
344 | 284 | }, | ||
345 | 285 | u'maasserver.nodegroupinterface': { | ||
346 | 286 | 'Meta': {'unique_together': "((u'nodegroup', u'interface'),)", 'object_name': 'NodeGroupInterface'}, | ||
347 | 287 | 'broadcast_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
348 | 288 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
349 | 289 | 'foreign_dhcp_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
350 | 290 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
351 | 291 | 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
352 | 292 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39'}), | ||
353 | 293 | 'ip_range_high': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
354 | 294 | 'ip_range_low': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
355 | 295 | 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
356 | 296 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
357 | 297 | 'router_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
358 | 298 | 'static_ip_range_high': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
359 | 299 | 'static_ip_range_low': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
360 | 300 | 'subnet_mask': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
361 | 301 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
362 | 302 | }, | ||
363 | 303 | u'maasserver.sshkey': { | ||
364 | 304 | 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'}, | ||
365 | 305 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
366 | 306 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
367 | 307 | 'key': ('django.db.models.fields.TextField', [], {}), | ||
368 | 308 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
369 | 309 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) | ||
370 | 310 | }, | ||
371 | 311 | u'maasserver.sslkey': { | ||
372 | 312 | 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSLKey'}, | ||
373 | 313 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
374 | 314 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
375 | 315 | 'key': ('django.db.models.fields.TextField', [], {}), | ||
376 | 316 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
377 | 317 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) | ||
378 | 318 | }, | ||
379 | 319 | u'maasserver.staticipaddress': { | ||
380 | 320 | 'Meta': {'object_name': 'StaticIPAddress'}, | ||
381 | 321 | 'alloc_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
382 | 322 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
383 | 323 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
384 | 324 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
385 | 325 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
386 | 326 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) | ||
387 | 327 | }, | ||
388 | 328 | u'maasserver.tag': { | ||
389 | 329 | 'Meta': {'object_name': 'Tag'}, | ||
390 | 330 | 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
391 | 331 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
392 | 332 | 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
393 | 333 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
394 | 334 | 'kernel_opts': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), | ||
395 | 335 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}), | ||
396 | 336 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
397 | 337 | }, | ||
398 | 338 | u'maasserver.userprofile': { | ||
399 | 339 | 'Meta': {'object_name': 'UserProfile'}, | ||
400 | 340 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
401 | 341 | 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) | ||
402 | 342 | }, | ||
403 | 343 | u'maasserver.zone': { | ||
404 | 344 | 'Meta': {'ordering': "[u'name']", 'object_name': 'Zone'}, | ||
405 | 345 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
406 | 346 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
407 | 347 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
408 | 348 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}), | ||
409 | 349 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
410 | 350 | }, | ||
411 | 351 | u'piston.consumer': { | ||
412 | 352 | 'Meta': {'object_name': 'Consumer'}, | ||
413 | 353 | 'description': ('django.db.models.fields.TextField', [], {}), | ||
414 | 354 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
415 | 355 | 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}), | ||
416 | 356 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
417 | 357 | 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}), | ||
418 | 358 | 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}), | ||
419 | 359 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': u"orm['auth.User']"}) | ||
420 | 360 | }, | ||
421 | 361 | u'piston.token': { | ||
422 | 362 | 'Meta': {'object_name': 'Token'}, | ||
423 | 363 | 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
424 | 364 | 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
425 | 365 | 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Consumer']"}), | ||
426 | 366 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
427 | 367 | 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
428 | 368 | 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}), | ||
429 | 369 | 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}), | ||
430 | 370 | 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1404804793L'}), | ||
431 | 371 | 'token_type': ('django.db.models.fields.IntegerField', [], {}), | ||
432 | 372 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': u"orm['auth.User']"}), | ||
433 | 373 | 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'}) | ||
434 | 374 | } | ||
435 | 375 | } | ||
436 | 376 | |||
437 | 377 | complete_apps = ['maasserver'] | ||
438 | 0 | \ No newline at end of file | 378 | \ No newline at end of file |
439 | 1 | 379 | ||
440 | === modified file 'src/maasserver/models/dhcplease.py' | |||
441 | --- src/maasserver/models/dhcplease.py 2014-07-03 12:29:46 +0000 | |||
442 | +++ src/maasserver/models/dhcplease.py 2014-07-08 07:55:43 +0000 | |||
443 | @@ -20,7 +20,6 @@ | |||
444 | 20 | from django.db import connection | 20 | from django.db import connection |
445 | 21 | from django.db.models import ( | 21 | from django.db.models import ( |
446 | 22 | ForeignKey, | 22 | ForeignKey, |
447 | 23 | IPAddressField, | ||
448 | 24 | Manager, | 23 | Manager, |
449 | 25 | Model, | 24 | Model, |
450 | 26 | ) | 25 | ) |
451 | @@ -28,7 +27,10 @@ | |||
452 | 28 | from django.dispatch import receiver | 27 | from django.dispatch import receiver |
453 | 29 | from maasserver import DefaultMeta | 28 | from maasserver import DefaultMeta |
454 | 30 | from maasserver.enum import NODE_STATUS | 29 | from maasserver.enum import NODE_STATUS |
456 | 31 | from maasserver.fields import MACAddressField | 30 | from maasserver.fields import ( |
457 | 31 | MAASIPAddressField, | ||
458 | 32 | MACAddressField, | ||
459 | 33 | ) | ||
460 | 32 | from maasserver.models.cleansave import CleanSave | 34 | from maasserver.models.cleansave import CleanSave |
461 | 33 | from maasserver.models.macaddress import MACAddress | 35 | from maasserver.models.macaddress import MACAddress |
462 | 34 | from maasserver.utils import strip_domain | 36 | from maasserver.utils import strip_domain |
463 | @@ -159,7 +161,7 @@ | |||
464 | 159 | objects = DHCPLeaseManager() | 161 | objects = DHCPLeaseManager() |
465 | 160 | 162 | ||
466 | 161 | nodegroup = ForeignKey('maasserver.NodeGroup', null=False, editable=False) | 163 | nodegroup = ForeignKey('maasserver.NodeGroup', null=False, editable=False) |
468 | 162 | ip = IPAddressField(null=False, editable=False, unique=True) | 164 | ip = MAASIPAddressField(null=False, editable=False, unique=True) |
469 | 163 | mac = MACAddressField(null=False, editable=False, unique=False) | 165 | mac = MACAddressField(null=False, editable=False, unique=False) |
470 | 164 | 166 | ||
471 | 165 | def __unicode__(self): | 167 | def __unicode__(self): |
472 | 166 | 168 | ||
473 | === modified file 'src/maasserver/models/network.py' | |||
474 | --- src/maasserver/models/network.py 2014-06-30 14:46:10 +0000 | |||
475 | +++ src/maasserver/models/network.py 2014-07-08 07:55:43 +0000 | |||
476 | @@ -27,13 +27,13 @@ | |||
477 | 27 | from django.core.validators import RegexValidator | 27 | from django.core.validators import RegexValidator |
478 | 28 | from django.db.models import ( | 28 | from django.db.models import ( |
479 | 29 | CharField, | 29 | CharField, |
480 | 30 | GenericIPAddressField, | ||
481 | 31 | Manager, | 30 | Manager, |
482 | 32 | Model, | 31 | Model, |
483 | 33 | PositiveSmallIntegerField, | 32 | PositiveSmallIntegerField, |
484 | 34 | TextField, | 33 | TextField, |
485 | 35 | ) | 34 | ) |
486 | 36 | from maasserver import DefaultMeta | 35 | from maasserver import DefaultMeta |
487 | 36 | from maasserver.fields import MAASIPAddressField | ||
488 | 37 | from maasserver.models.cleansave import CleanSave | 37 | from maasserver.models.cleansave import CleanSave |
489 | 38 | from netaddr import IPAddress | 38 | from netaddr import IPAddress |
490 | 39 | from netaddr.core import AddrFormatError | 39 | from netaddr.core import AddrFormatError |
491 | @@ -220,11 +220,11 @@ | |||
492 | 220 | validators=[NETWORK_NAME_VALIDATOR], | 220 | validators=[NETWORK_NAME_VALIDATOR], |
493 | 221 | help_text="Identifying name for this network.") | 221 | help_text="Identifying name for this network.") |
494 | 222 | 222 | ||
496 | 223 | ip = GenericIPAddressField( | 223 | ip = MAASIPAddressField( |
497 | 224 | blank=False, editable=True, unique=True, null=False, | 224 | blank=False, editable=True, unique=True, null=False, |
498 | 225 | help_text="Network address (e.g. 192.168.1.0).") | 225 | help_text="Network address (e.g. 192.168.1.0).") |
499 | 226 | 226 | ||
501 | 227 | netmask = GenericIPAddressField( | 227 | netmask = MAASIPAddressField( |
502 | 228 | blank=False, editable=True, null=False, | 228 | blank=False, editable=True, null=False, |
503 | 229 | help_text="Network mask (e.g. 255.255.255.0).") | 229 | help_text="Network mask (e.g. 255.255.255.0).") |
504 | 230 | 230 | ||
505 | 231 | 231 | ||
506 | === modified file 'src/maasserver/models/nodegroupinterface.py' | |||
507 | --- src/maasserver/models/nodegroupinterface.py 2014-07-07 09:31:31 +0000 | |||
508 | +++ src/maasserver/models/nodegroupinterface.py 2014-07-08 07:55:43 +0000 | |||
509 | @@ -23,7 +23,6 @@ | |||
510 | 23 | from django.db.models import ( | 23 | from django.db.models import ( |
511 | 24 | CharField, | 24 | CharField, |
512 | 25 | ForeignKey, | 25 | ForeignKey, |
513 | 26 | GenericIPAddressField, | ||
514 | 27 | IntegerField, | 26 | IntegerField, |
515 | 28 | ) | 27 | ) |
516 | 29 | from maasserver import DefaultMeta | 28 | from maasserver import DefaultMeta |
517 | @@ -32,6 +31,7 @@ | |||
518 | 32 | NODEGROUPINTERFACE_MANAGEMENT_CHOICES, | 31 | NODEGROUPINTERFACE_MANAGEMENT_CHOICES, |
519 | 33 | NODEGROUPINTERFACE_MANAGEMENT_CHOICES_DICT, | 32 | NODEGROUPINTERFACE_MANAGEMENT_CHOICES_DICT, |
520 | 34 | ) | 33 | ) |
521 | 34 | from maasserver.fields import MAASIPAddressField | ||
522 | 35 | from maasserver.models.cleansave import CleanSave | 35 | from maasserver.models.cleansave import CleanSave |
523 | 36 | from maasserver.models.timestampedmodel import TimestampedModel | 36 | from maasserver.models.timestampedmodel import TimestampedModel |
524 | 37 | from netaddr import ( | 37 | from netaddr import ( |
525 | @@ -55,7 +55,7 @@ | |||
526 | 55 | unique_together = ('nodegroup', 'interface') | 55 | unique_together = ('nodegroup', 'interface') |
527 | 56 | 56 | ||
528 | 57 | # Static IP of the interface. | 57 | # Static IP of the interface. |
530 | 58 | ip = GenericIPAddressField( | 58 | ip = MAASIPAddressField( |
531 | 59 | null=False, editable=True, | 59 | null=False, editable=True, |
532 | 60 | help_text="Static IP Address of the interface", | 60 | help_text="Static IP Address of the interface", |
533 | 61 | verbose_name="IP") | 61 | verbose_name="IP") |
534 | @@ -72,33 +72,33 @@ | |||
535 | 72 | interface = CharField( | 72 | interface = CharField( |
536 | 73 | blank=True, editable=True, max_length=255, default='', | 73 | blank=True, editable=True, max_length=255, default='', |
537 | 74 | help_text="Name of this interface (e.g. 'em1').") | 74 | help_text="Name of this interface (e.g. 'em1').") |
539 | 75 | subnet_mask = GenericIPAddressField( | 75 | subnet_mask = MAASIPAddressField( |
540 | 76 | editable=True, unique=False, blank=True, null=True, default=None, | 76 | editable=True, unique=False, blank=True, null=True, default=None, |
541 | 77 | help_text="e.g. 255.255.255.0") | 77 | help_text="e.g. 255.255.255.0") |
543 | 78 | broadcast_ip = GenericIPAddressField( | 78 | broadcast_ip = MAASIPAddressField( |
544 | 79 | editable=True, unique=False, blank=True, null=True, default=None, | 79 | editable=True, unique=False, blank=True, null=True, default=None, |
545 | 80 | verbose_name="Broadcast IP", | 80 | verbose_name="Broadcast IP", |
546 | 81 | help_text="e.g. 192.168.1.255") | 81 | help_text="e.g. 192.168.1.255") |
548 | 82 | router_ip = GenericIPAddressField( | 82 | router_ip = MAASIPAddressField( |
549 | 83 | editable=True, unique=False, blank=True, null=True, default=None, | 83 | editable=True, unique=False, blank=True, null=True, default=None, |
550 | 84 | verbose_name="Router IP", | 84 | verbose_name="Router IP", |
551 | 85 | help_text="IP of this network's router given to DHCP clients") | 85 | help_text="IP of this network's router given to DHCP clients") |
553 | 86 | ip_range_low = GenericIPAddressField( | 86 | ip_range_low = MAASIPAddressField( |
554 | 87 | editable=True, unique=False, blank=True, null=True, default=None, | 87 | editable=True, unique=False, blank=True, null=True, default=None, |
555 | 88 | verbose_name="DHCP dynamic IP range low value", | 88 | verbose_name="DHCP dynamic IP range low value", |
556 | 89 | help_text="Lowest IP number of the range for dynamic IPs, used for " | 89 | help_text="Lowest IP number of the range for dynamic IPs, used for " |
557 | 90 | "enlistment, commissioning and unknown devices.") | 90 | "enlistment, commissioning and unknown devices.") |
559 | 91 | ip_range_high = GenericIPAddressField( | 91 | ip_range_high = MAASIPAddressField( |
560 | 92 | editable=True, unique=False, blank=True, null=True, default=None, | 92 | editable=True, unique=False, blank=True, null=True, default=None, |
561 | 93 | verbose_name="DHCP dynamic IP range high value", | 93 | verbose_name="DHCP dynamic IP range high value", |
562 | 94 | help_text="Highest IP number of the range for dynamic IPs, used for " | 94 | help_text="Highest IP number of the range for dynamic IPs, used for " |
563 | 95 | "enlistment, commissioning and unknown devices.") | 95 | "enlistment, commissioning and unknown devices.") |
565 | 96 | static_ip_range_low = GenericIPAddressField( | 96 | static_ip_range_low = MAASIPAddressField( |
566 | 97 | editable=True, unique=False, blank=True, null=True, default=None, | 97 | editable=True, unique=False, blank=True, null=True, default=None, |
567 | 98 | verbose_name="Static IP range low value", | 98 | verbose_name="Static IP range low value", |
568 | 99 | help_text="Lowest IP number of the range for IPs given to allocated " | 99 | help_text="Lowest IP number of the range for IPs given to allocated " |
569 | 100 | "nodes, must be in same network as dynamic range.") | 100 | "nodes, must be in same network as dynamic range.") |
571 | 101 | static_ip_range_high = GenericIPAddressField( | 101 | static_ip_range_high = MAASIPAddressField( |
572 | 102 | editable=True, unique=False, blank=True, null=True, default=None, | 102 | editable=True, unique=False, blank=True, null=True, default=None, |
573 | 103 | verbose_name="Static IP range high value", | 103 | verbose_name="Static IP range high value", |
574 | 104 | help_text="Highest IP number of the range for IPs given to allocated " | 104 | help_text="Highest IP number of the range for IPs given to allocated " |
575 | @@ -106,7 +106,7 @@ | |||
576 | 106 | 106 | ||
577 | 107 | # Foreign DHCP server address, if any, that was detected on this | 107 | # Foreign DHCP server address, if any, that was detected on this |
578 | 108 | # interface. | 108 | # interface. |
580 | 109 | foreign_dhcp_ip = GenericIPAddressField( | 109 | foreign_dhcp_ip = MAASIPAddressField( |
581 | 110 | null=True, default=None, editable=True, blank=True, unique=False) | 110 | null=True, default=None, editable=True, blank=True, unique=False) |
582 | 111 | 111 | ||
583 | 112 | @property | 112 | @property |
584 | @@ -120,7 +120,7 @@ | |||
585 | 120 | ip = self.ip | 120 | ip = self.ip |
586 | 121 | netmask = self.subnet_mask | 121 | netmask = self.subnet_mask |
587 | 122 | # Nullness check for GenericIPAddress fields is deliberately kept | 122 | # Nullness check for GenericIPAddress fields is deliberately kept |
589 | 123 | # vague: GenericIPAddressField seems to represent nulls as empty | 123 | # vague: MAASIPAddressField seems to represent nulls as empty |
590 | 124 | # strings. | 124 | # strings. |
591 | 125 | if netmask: | 125 | if netmask: |
592 | 126 | return make_network(ip, netmask).cidr | 126 | return make_network(ip, netmask).cidr |
593 | 127 | 127 | ||
594 | === modified file 'src/maasserver/models/staticipaddress.py' | |||
595 | --- src/maasserver/models/staticipaddress.py 2014-07-07 10:14:12 +0000 | |||
596 | +++ src/maasserver/models/staticipaddress.py 2014-07-08 07:55:43 +0000 | |||
597 | @@ -28,13 +28,13 @@ | |||
598 | 28 | from django.db import connection | 28 | from django.db import connection |
599 | 29 | from django.db.models import ( | 29 | from django.db.models import ( |
600 | 30 | ForeignKey, | 30 | ForeignKey, |
601 | 31 | GenericIPAddressField, | ||
602 | 32 | IntegerField, | 31 | IntegerField, |
603 | 33 | Manager, | 32 | Manager, |
604 | 34 | ) | 33 | ) |
605 | 35 | from maasserver import DefaultMeta | 34 | from maasserver import DefaultMeta |
606 | 36 | from maasserver.enum import IPADDRESS_TYPE | 35 | from maasserver.enum import IPADDRESS_TYPE |
607 | 37 | from maasserver.exceptions import StaticIPAddressExhaustion | 36 | from maasserver.exceptions import StaticIPAddressExhaustion |
608 | 37 | from maasserver.fields import MAASIPAddressField | ||
609 | 38 | from maasserver.models.cleansave import CleanSave | 38 | from maasserver.models.cleansave import CleanSave |
610 | 39 | from maasserver.models.timestampedmodel import TimestampedModel | 39 | from maasserver.models.timestampedmodel import TimestampedModel |
611 | 40 | from maasserver.utils import strip_domain | 40 | from maasserver.utils import strip_domain |
612 | @@ -82,16 +82,7 @@ | |||
613 | 82 | # When we do ipv6, this needs changing. | 82 | # When we do ipv6, this needs changing. |
614 | 83 | range_list = [ip.ipv4().format() for ip in static_range] | 83 | range_list = [ip.ipv4().format() for ip in static_range] |
615 | 84 | 84 | ||
626 | 85 | # We're using a raw query to bypass a bug in Django that inserts | 85 | existing = self.filter(ip__gte=range_low, ip__lte=range_high) |
617 | 86 | # a HOST() cast on the IP, causing the wrong comparison on the | ||
618 | 87 | # IP field. | ||
619 | 88 | # https://code.djangoproject.com/ticket/11442 | ||
620 | 89 | existing = StaticIPAddress.objects.raw( | ||
621 | 90 | """ | ||
622 | 91 | SELECT * FROM maasserver_staticipaddress | ||
623 | 92 | WHERE IP >= %s AND IP <= %s | ||
624 | 93 | """, | ||
625 | 94 | [range_low, range_high]) | ||
627 | 95 | 86 | ||
628 | 96 | # Calculate the set of available IPs. This will be inefficient | 87 | # Calculate the set of available IPs. This will be inefficient |
629 | 97 | # with large sets, but it will do for now. | 88 | # with large sets, but it will do for now. |
630 | @@ -169,7 +160,7 @@ | |||
631 | 169 | verbose_name = "Static IP Address" | 160 | verbose_name = "Static IP Address" |
632 | 170 | verbose_name_plural = "Static IP Addresses" | 161 | verbose_name_plural = "Static IP Addresses" |
633 | 171 | 162 | ||
635 | 172 | ip = GenericIPAddressField( | 163 | ip = MAASIPAddressField( |
636 | 173 | unique=True, null=False, editable=False, blank=False, | 164 | unique=True, null=False, editable=False, blank=False, |
637 | 174 | verbose_name='IP') | 165 | verbose_name='IP') |
638 | 175 | 166 | ||
639 | 176 | 167 | ||
640 | === modified file 'src/maasserver/tests/models.py' | |||
641 | --- src/maasserver/tests/models.py 2013-10-07 09:12:40 +0000 | |||
642 | +++ src/maasserver/tests/models.py 2014-07-08 07:55:43 +0000 | |||
643 | @@ -13,6 +13,7 @@ | |||
644 | 13 | 13 | ||
645 | 14 | __metaclass__ = type | 14 | __metaclass__ = type |
646 | 15 | __all__ = [ | 15 | __all__ = [ |
647 | 16 | 'MAASIPAddressFieldModel', | ||
648 | 16 | 'JSONFieldModel', | 17 | 'JSONFieldModel', |
649 | 17 | 'FieldChangeTestModel', | 18 | 'FieldChangeTestModel', |
650 | 18 | ] | 19 | ] |
651 | @@ -24,6 +25,7 @@ | |||
652 | 24 | ) | 25 | ) |
653 | 25 | from maasserver.fields import ( | 26 | from maasserver.fields import ( |
654 | 26 | JSONObjectField, | 27 | JSONObjectField, |
655 | 28 | MAASIPAddressField, | ||
656 | 27 | XMLField, | 29 | XMLField, |
657 | 28 | ) | 30 | ) |
658 | 29 | from maasserver.models.managers import BulkManager | 31 | from maasserver.models.managers import BulkManager |
659 | @@ -67,3 +69,7 @@ | |||
660 | 67 | parent = ForeignKey('BulkManagerParentTestModel', editable=False) | 69 | parent = ForeignKey('BulkManagerParentTestModel', editable=False) |
661 | 68 | 70 | ||
662 | 69 | objects = BulkManager() | 71 | objects = BulkManager() |
663 | 72 | |||
664 | 73 | |||
665 | 74 | class MAASIPAddressFieldModel(Model): | ||
666 | 75 | ip_address = MAASIPAddressField() | ||
667 | 70 | 76 | ||
668 | === modified file 'src/maasserver/tests/test_fields.py' | |||
669 | --- src/maasserver/tests/test_fields.py 2014-07-02 07:05:24 +0000 | |||
670 | +++ src/maasserver/tests/test_fields.py 2014-07-08 07:55:43 +0000 | |||
671 | @@ -42,6 +42,7 @@ | |||
672 | 42 | from maasserver.testing.testcase import MAASServerTestCase | 42 | from maasserver.testing.testcase import MAASServerTestCase |
673 | 43 | from maasserver.tests.models import ( | 43 | from maasserver.tests.models import ( |
674 | 44 | JSONFieldModel, | 44 | JSONFieldModel, |
675 | 45 | MAASIPAddressFieldModel, | ||
676 | 45 | XMLFieldModel, | 46 | XMLFieldModel, |
677 | 46 | ) | 47 | ) |
678 | 47 | from maastesting.djangotestcase import TestModelMixin | 48 | from maastesting.djangotestcase import TestModelMixin |
679 | @@ -388,3 +389,15 @@ | |||
680 | 388 | 389 | ||
681 | 389 | def test_is_editable(self): | 390 | def test_is_editable(self): |
682 | 390 | self.assertTrue(EditableBinaryField().editable) | 391 | self.assertTrue(EditableBinaryField().editable) |
683 | 392 | |||
684 | 393 | |||
685 | 394 | class TestMAASIPAddressField(TestModelMixin, MAASServerTestCase): | ||
686 | 395 | |||
687 | 396 | app = 'maasserver.tests' | ||
688 | 397 | |||
689 | 398 | def test_uses_ip_comparison(self): | ||
690 | 399 | ip_object = MAASIPAddressFieldModel.objects.create( | ||
691 | 400 | ip_address='192.0.2.99') | ||
692 | 401 | results = MAASIPAddressFieldModel.objects.filter( | ||
693 | 402 | ip_address__lte='192.0.2.100') | ||
694 | 403 | self.assertItemsEqual([ip_object], results) |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Please let's not have a repeat of the TestCase debacle, and call this Field instead.
*MAAS*IPAddress
Also, surprised it needs a migration just for a field name change. www.enigmail. net/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: Using GnuPG with Thunderbird - http://
iEYEARECAAYFAlO 7RT4ACgkQWhGlTF 8G/HdakQCgjBvFZ WZz+LoW6eoa8NFq mDO/ meBy0zTqgg0eKsi Fp
bSEAnipHz21PGLP
=E/ET
-----END PGP SIGNATURE-----