Merge lp:~julian-edwards/maas/default-gateway-for-networks into lp:~maas-committers/maas/trunk

Proposed by Julian Edwards
Status: Merged
Approved by: Julian Edwards
Approved revision: no longer in the source branch.
Merged at revision: 2853
Proposed branch: lp:~julian-edwards/maas/default-gateway-for-networks
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 433 lines (+388/-0)
4 files modified
src/maasserver/api/tests/test_nodegroup.py (+7/-0)
src/maasserver/forms.py (+1/-0)
src/maasserver/migrations/0107_add_default_gateway_to_network.py (+376/-0)
src/maasserver/models/network.py (+4/-0)
To merge this branch: bzr merge lp:~julian-edwards/maas/default-gateway-for-networks
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) Approve
Review via email: mp+232835@code.launchpad.net

Commit message

Model change to Network to add default_gateway, its migration, and a small change to propagate router_ip from cluster interfaces into the Network at the same time all the other data is copied over.

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

I wonder if the default gateway is expected always to be on the same subnet. It's the sort of restriction that can be hard to add later.

review: Approve
Revision history for this message
Julian Edwards (julian-edwards) wrote :

On Monday 01 Sep 2014 03:26:12 you wrote:
> Review: Approve
>
> I wonder if the default gateway is expected always to be on the same subnet.
> It's the sort of restriction that can be hard to add later.

Yeah interesting point.

One part of me wants to enforce it, the other part doesn't want to be too
prescriptive "just in case".

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api/tests/test_nodegroup.py'
2--- src/maasserver/api/tests/test_nodegroup.py 2014-08-26 18:01:08 +0000
3+++ src/maasserver/api/tests/test_nodegroup.py 2014-09-01 03:15:35 +0000
4@@ -77,6 +77,7 @@
5 from testtools.matchers import (
6 AllMatch,
7 Equals,
8+ MatchesStructure,
9 )
10
11
12@@ -891,6 +892,12 @@
13 for net, mac in expected_relations:
14 [observed_macddress] = net.macaddress_set.all()
15 self.expectThat(mac, Equals(observed_macddress))
16+ interface = mac_addresses[mac]
17+ self.expectThat(
18+ net, MatchesStructure.byEquality(
19+ default_gateway=interface.router_ip,
20+ netmask=interface.subnet_mask,
21+ ))
22
23 def test_does_not_overwrite_network_with_same_name(self):
24 cluster = factory.make_node_group()
25
26=== modified file 'src/maasserver/forms.py'
27--- src/maasserver/forms.py 2014-08-31 02:47:48 +0000
28+++ src/maasserver/forms.py 2014-09-01 03:15:35 +0000
29@@ -1184,6 +1184,7 @@
30 name=name,
31 ip=unicode(ipnetwork.network),
32 netmask=unicode(ipnetwork.netmask),
33+ default_gateway=interface.router_ip,
34 vlan_tag=vlan_tag,
35 description=(
36 "Auto created when creating interface %s on cluster "
37
38=== added file 'src/maasserver/migrations/0107_add_default_gateway_to_network.py'
39--- src/maasserver/migrations/0107_add_default_gateway_to_network.py 1970-01-01 00:00:00 +0000
40+++ src/maasserver/migrations/0107_add_default_gateway_to_network.py 2014-09-01 03:15:35 +0000
41@@ -0,0 +1,376 @@
42+from django.db import models
43+from south.db import db
44+# -*- coding: utf-8 -*-
45+from south.utils import datetime_utils as datetime
46+from south.v2 import SchemaMigration
47+
48+
49+class Migration(SchemaMigration):
50+
51+ def forwards(self, orm):
52+ # Adding field 'Network.default_gateway'
53+ db.add_column(u'maasserver_network', 'default_gateway',
54+ self.gf('maasserver.fields.MAASIPAddressField')(max_length=39, null=True, blank=True),
55+ keep_default=False)
56+
57+
58+ def backwards(self, orm):
59+ # Deleting field 'Network.default_gateway'
60+ db.delete_column(u'maasserver_network', 'default_gateway')
61+
62+
63+ models = {
64+ u'auth.group': {
65+ 'Meta': {'object_name': 'Group'},
66+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
68+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
69+ },
70+ u'auth.permission': {
71+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
72+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
73+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
74+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
75+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
76+ },
77+ u'auth.user': {
78+ 'Meta': {'object_name': 'User'},
79+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
80+ 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}),
81+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
82+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
83+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
84+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
85+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
86+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
87+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
88+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
89+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
90+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
91+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
92+ },
93+ u'contenttypes.contenttype': {
94+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
95+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
96+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
97+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
98+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
99+ },
100+ u'maasserver.bootimage': {
101+ 'Meta': {'unique_together': "((u'nodegroup', u'osystem', u'architecture', u'subarchitecture', u'release', u'purpose', u'label'),)", 'object_name': 'BootImage'},
102+ 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
103+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
104+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
105+ 'label': ('django.db.models.fields.CharField', [], {'default': "u'release'", 'max_length': '255'}),
106+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
107+ 'osystem': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
108+ 'purpose': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
109+ 'release': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
110+ 'subarchitecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
111+ 'supported_subarches': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
112+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
113+ 'xinstall_path': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
114+ 'xinstall_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '30', 'null': 'True', 'blank': 'True'})
115+ },
116+ u'maasserver.bootresource': {
117+ 'Meta': {'unique_together': "((u'name', u'architecture'),)", 'object_name': 'BootResource'},
118+ 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
119+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
120+ 'extra': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
121+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
122+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
123+ 'rtype': ('django.db.models.fields.IntegerField', [], {'max_length': '10'}),
124+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
125+ },
126+ u'maasserver.bootresourcefile': {
127+ 'Meta': {'unique_together': "((u'resource_set', u'filetype'),)", 'object_name': 'BootResourceFile'},
128+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
129+ 'extra': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
130+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
131+ 'filetype': ('django.db.models.fields.CharField', [], {'default': "u'root-tgz'", 'max_length': '20'}),
132+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
133+ 'largefile': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.LargeFile']"}),
134+ 'resource_set': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'files'", 'to': u"orm['maasserver.BootResourceSet']"}),
135+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
136+ },
137+ u'maasserver.bootresourceset': {
138+ 'Meta': {'unique_together': "((u'resource', u'version'),)", 'object_name': 'BootResourceSet'},
139+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
140+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
141+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
142+ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'sets'", 'to': u"orm['maasserver.BootResource']"}),
143+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
144+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '255'})
145+ },
146+ u'maasserver.bootsource': {
147+ 'Meta': {'object_name': 'BootSource'},
148+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
149+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
150+ 'keyring_data': ('maasserver.fields.EditableBinaryField', [], {'blank': 'True'}),
151+ 'keyring_filename': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}),
152+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
153+ 'url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200'})
154+ },
155+ u'maasserver.bootsourceselection': {
156+ 'Meta': {'object_name': 'BootSourceSelection'},
157+ 'arches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}),
158+ 'boot_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.BootSource']"}),
159+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
160+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
161+ 'labels': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}),
162+ 'os': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}),
163+ 'release': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}),
164+ 'subarches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}),
165+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
166+ },
167+ u'maasserver.candidatename': {
168+ 'Meta': {'unique_together': "((u'name', u'position'),)", 'object_name': 'CandidateName'},
169+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
170+ 'name': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
171+ 'position': ('django.db.models.fields.IntegerField', [], {})
172+ },
173+ u'maasserver.componenterror': {
174+ 'Meta': {'object_name': 'ComponentError'},
175+ 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
176+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
177+ 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
178+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
179+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
180+ },
181+ u'maasserver.config': {
182+ 'Meta': {'object_name': 'Config'},
183+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
184+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
185+ 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'})
186+ },
187+ u'maasserver.dhcplease': {
188+ 'Meta': {'object_name': 'DHCPLease'},
189+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
190+ 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}),
191+ 'mac': ('maasserver.fields.MACAddressField', [], {}),
192+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"})
193+ },
194+ u'maasserver.downloadprogress': {
195+ 'Meta': {'object_name': 'DownloadProgress'},
196+ 'bytes_downloaded': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
197+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
198+ 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}),
199+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
200+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
201+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
202+ 'size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
203+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
204+ },
205+ u'maasserver.event': {
206+ 'Meta': {'object_name': 'Event'},
207+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
208+ 'description': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}),
209+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
210+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}),
211+ 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.EventType']"}),
212+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
213+ },
214+ u'maasserver.eventtype': {
215+ 'Meta': {'object_name': 'EventType'},
216+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
217+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
218+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
219+ 'level': ('django.db.models.fields.IntegerField', [], {}),
220+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
221+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
222+ },
223+ u'maasserver.filestorage': {
224+ 'Meta': {'unique_together': "((u'filename', u'owner'),)", 'object_name': 'FileStorage'},
225+ 'content': ('metadataserver.fields.BinaryField', [], {'blank': 'True'}),
226+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
227+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
228+ 'key': ('django.db.models.fields.CharField', [], {'default': "u'8b7df110-3179-11e4-ae4e-0026c71eea0e'", 'unique': 'True', 'max_length': '36'}),
229+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
230+ },
231+ u'maasserver.largefile': {
232+ 'Meta': {'object_name': 'LargeFile'},
233+ 'content': ('maasserver.fields.LargeObjectField', [], {}),
234+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
235+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
236+ 'sha256': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
237+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {}),
238+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
239+ },
240+ u'maasserver.licensekey': {
241+ 'Meta': {'unique_together': "((u'osystem', u'distro_series'),)", 'object_name': 'LicenseKey'},
242+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
243+ 'distro_series': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
244+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
245+ 'license_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
246+ 'osystem': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
247+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
248+ },
249+ u'maasserver.macaddress': {
250+ 'Meta': {'ordering': "(u'created',)", 'object_name': 'MACAddress'},
251+ 'cluster_interface': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['maasserver.NodeGroupInterface']", 'null': 'True', 'blank': 'True'}),
252+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
253+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
254+ 'ip_addresses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.StaticIPAddress']", 'symmetrical': 'False', 'through': u"orm['maasserver.MACStaticIPAddressLink']", 'blank': 'True'}),
255+ 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}),
256+ 'networks': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Network']", 'symmetrical': 'False', 'blank': 'True'}),
257+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}),
258+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
259+ },
260+ u'maasserver.macstaticipaddresslink': {
261+ 'Meta': {'unique_together': "((u'ip_address', u'mac_address'),)", 'object_name': 'MACStaticIPAddressLink'},
262+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
263+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
264+ 'ip_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.StaticIPAddress']", 'unique': 'True'}),
265+ 'mac_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.MACAddress']"}),
266+ 'nic_alias': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
267+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
268+ },
269+ u'maasserver.network': {
270+ 'Meta': {'object_name': 'Network'},
271+ 'default_gateway': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39', 'null': 'True', 'blank': 'True'}),
272+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
273+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
274+ 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}),
275+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
276+ 'netmask': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39'}),
277+ 'vlan_tag': ('django.db.models.fields.PositiveSmallIntegerField', [], {'unique': 'True', 'null': 'True', 'blank': 'True'})
278+ },
279+ u'maasserver.node': {
280+ 'Meta': {'object_name': 'Node'},
281+ 'agent_name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
282+ 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '31'}),
283+ 'boot_type': ('django.db.models.fields.CharField', [], {'default': "u'fastpath'", 'max_length': '20'}),
284+ 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
285+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
286+ 'disable_ipv4': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
287+ 'distro_series': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}),
288+ 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
289+ 'error_description': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}),
290+ 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'unique': 'True', 'max_length': '255', 'blank': 'True'}),
291+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
292+ 'license_key': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
293+ 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
294+ 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
295+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}),
296+ 'osystem': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}),
297+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
298+ 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
299+ 'power_state': ('django.db.models.fields.CharField', [], {'default': "u'unknown'", 'max_length': '10'}),
300+ 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}),
301+ 'routers': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'macaddr'", 'null': 'True', 'blank': 'True'}),
302+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}),
303+ 'storage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
304+ 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-8b7fc760-3179-11e4-ae4e-0026c71eea0e'", 'unique': 'True', 'max_length': '41'}),
305+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}),
306+ 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'null': 'True'}),
307+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
308+ 'zone': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Zone']", 'on_delete': 'models.SET_DEFAULT'})
309+ },
310+ u'maasserver.nodegroup': {
311+ 'Meta': {'object_name': 'NodeGroup'},
312+ 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}),
313+ 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'unique': 'True'}),
314+ 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}),
315+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
316+ 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
317+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
318+ 'maas_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
319+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
320+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
321+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
322+ 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'})
323+ },
324+ u'maasserver.nodegroupinterface': {
325+ 'Meta': {'unique_together': "((u'nodegroup', u'name'),)", 'object_name': 'NodeGroupInterface'},
326+ 'broadcast_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
327+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
328+ 'foreign_dhcp_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
329+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
330+ 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
331+ 'ip': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39'}),
332+ 'ip_range_high': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
333+ 'ip_range_low': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
334+ 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
335+ 'name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
336+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
337+ 'router_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
338+ 'static_ip_range_high': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
339+ 'static_ip_range_low': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
340+ 'subnet_mask': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
341+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
342+ },
343+ u'maasserver.sshkey': {
344+ 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'},
345+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
346+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
347+ 'key': ('django.db.models.fields.TextField', [], {}),
348+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
349+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
350+ },
351+ u'maasserver.sslkey': {
352+ 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSLKey'},
353+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
354+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
355+ 'key': ('django.db.models.fields.TextField', [], {}),
356+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
357+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
358+ },
359+ u'maasserver.staticipaddress': {
360+ 'Meta': {'object_name': 'StaticIPAddress'},
361+ 'alloc_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
362+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
363+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
364+ 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}),
365+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
366+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
367+ },
368+ u'maasserver.tag': {
369+ 'Meta': {'object_name': 'Tag'},
370+ 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
371+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
372+ 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
373+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
374+ 'kernel_opts': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
375+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
376+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
377+ },
378+ u'maasserver.userprofile': {
379+ 'Meta': {'object_name': 'UserProfile'},
380+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
381+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
382+ },
383+ u'maasserver.zone': {
384+ 'Meta': {'ordering': "[u'name']", 'object_name': 'Zone'},
385+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
386+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
387+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
388+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
389+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
390+ },
391+ u'piston.consumer': {
392+ 'Meta': {'object_name': 'Consumer'},
393+ 'description': ('django.db.models.fields.TextField', [], {}),
394+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
395+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
396+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
397+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
398+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}),
399+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': u"orm['auth.User']"})
400+ },
401+ u'piston.token': {
402+ 'Meta': {'object_name': 'Token'},
403+ 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
404+ 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
405+ 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Consumer']"}),
406+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
407+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
408+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
409+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
410+ 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1409535882L'}),
411+ 'token_type': ('django.db.models.fields.IntegerField', [], {}),
412+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': u"orm['auth.User']"}),
413+ 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'})
414+ }
415+ }
416+
417+ complete_apps = ['maasserver']
418\ No newline at end of file
419
420=== modified file 'src/maasserver/models/network.py'
421--- src/maasserver/models/network.py 2014-08-13 21:49:35 +0000
422+++ src/maasserver/models/network.py 2014-09-01 03:15:35 +0000
423@@ -244,6 +244,10 @@
424 blank=False, editable=True, null=False,
425 help_text="Network mask (e.g. 255.255.255.0).")
426
427+ default_gateway = MAASIPAddressField(
428+ blank=True, editable=True, null=True,
429+ help_text="Default gateway for this network (e.g. 192.168.1.1).")
430+
431 vlan_tag = PositiveSmallIntegerField(
432 editable=True, null=True, blank=True, unique=True,
433 help_text="A 12-bit field specifying the VLAN to which the frame "