Merge lp:~rvb/maas/add-network-node-rel2 into lp:~maas-committers/maas/trunk

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 1885
Proposed branch: lp:~rvb/maas/add-network-node-rel2
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 574 lines (+282/-255)
4 files modified
src/maasserver/migrations/0066_rename_vlan_add_link_node_network.py (+268/-0)
src/maasserver/migrations/0066_replace_vlan_with_network.py (+0/-255)
src/maasserver/models/node.py (+3/-0)
src/maasserver/models/tests/test_node.py (+11/-0)
To merge this branch: bzr merge lp:~rvb/maas/add-network-node-rel2
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Review via email: mp+204617@code.launchpad.net

Commit message

Add a relation between nodes and networks.

Description of the change

(Fold 2 migrations into one.)

To post a comment you must log in.
Revision history for this message
Raphaël Badin (rvb) wrote :

Self-approving because this change has been approved by Julian in https://code.launchpad.net/~rvb/maas/add-network-node-rel/+merge/204506.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'src/maasserver/migrations/0066_rename_vlan_add_link_node_network.py'
2--- src/maasserver/migrations/0066_rename_vlan_add_link_node_network.py 1970-01-01 00:00:00 +0000
3+++ src/maasserver/migrations/0066_rename_vlan_add_link_node_network.py 2014-02-04 09:09:30 +0000
4@@ -0,0 +1,268 @@
5+# -*- coding: utf-8 -*-
6+import datetime
7+
8+from django.db import models
9+from south.db import db
10+from south.v2 import SchemaMigration
11+
12+
13+class Migration(SchemaMigration):
14+
15+ def forwards(self, orm):
16+ # Deleting model 'Vlan'
17+ db.delete_table(u'maasserver_vlan')
18+
19+ # Adding model 'Network'
20+ db.create_table(u'maasserver_network', (
21+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
22+ ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
23+ ('ip', self.gf('django.db.models.fields.GenericIPAddressField')(unique=True, max_length=39)),
24+ ('netmask', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39)),
25+ ('vlan_tag', self.gf('django.db.models.fields.PositiveSmallIntegerField')(unique=True)),
26+ ('description', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, blank=True)),
27+ ))
28+ db.send_create_signal(u'maasserver', ['Network'])
29+
30+ # Adding M2M table for field networks on 'Node'
31+ db.create_table(u'maasserver_node_networks', (
32+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
33+ ('node', models.ForeignKey(orm[u'maasserver.node'], null=False)),
34+ ('network', models.ForeignKey(orm[u'maasserver.network'], null=False))
35+ ))
36+ db.create_unique(u'maasserver_node_networks', ['node_id', 'network_id'])
37+
38+
39+ def backwards(self, orm):
40+ # Adding model 'Vlan'
41+ db.create_table(u'maasserver_vlan', (
42+ ('tag', self.gf('django.db.models.fields.PositiveSmallIntegerField')(unique=True)),
43+ ('description', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, blank=True)),
44+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
45+ ))
46+ db.send_create_signal(u'maasserver', ['Vlan'])
47+
48+ # Deleting model 'Network'
49+ db.delete_table(u'maasserver_network')
50+
51+ # Removing M2M table for field networks on 'Node'
52+ db.delete_table('maasserver_node_networks')
53+
54+
55+ models = {
56+ u'auth.group': {
57+ 'Meta': {'object_name': 'Group'},
58+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
59+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
60+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
61+ },
62+ u'auth.permission': {
63+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
64+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
65+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
66+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
68+ },
69+ u'auth.user': {
70+ 'Meta': {'object_name': 'User'},
71+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
72+ 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}),
73+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
74+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
75+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
76+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
77+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
78+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
79+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
80+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
81+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
82+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
83+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
84+ },
85+ u'contenttypes.contenttype': {
86+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
87+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
88+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
89+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
90+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
91+ },
92+ u'maasserver.bootimage': {
93+ 'Meta': {'unique_together': "((u'nodegroup', u'architecture', u'subarchitecture', u'release', u'purpose'),)", 'object_name': 'BootImage'},
94+ 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
95+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
96+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
97+ 'purpose': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
98+ 'release': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
99+ 'subarchitecture': ('django.db.models.fields.CharField', [], {'max_length': '255'})
100+ },
101+ u'maasserver.componenterror': {
102+ 'Meta': {'object_name': 'ComponentError'},
103+ 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
104+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
105+ 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
106+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
107+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
108+ },
109+ u'maasserver.config': {
110+ 'Meta': {'object_name': 'Config'},
111+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
112+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
113+ 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'})
114+ },
115+ u'maasserver.dhcplease': {
116+ 'Meta': {'object_name': 'DHCPLease'},
117+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
118+ 'ip': ('django.db.models.fields.IPAddressField', [], {'unique': 'True', 'max_length': '15'}),
119+ 'mac': ('maasserver.fields.MACAddressField', [], {}),
120+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"})
121+ },
122+ u'maasserver.downloadprogress': {
123+ 'Meta': {'object_name': 'DownloadProgress'},
124+ 'bytes_downloaded': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
125+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
126+ 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}),
127+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
128+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
129+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
130+ 'size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
131+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
132+ },
133+ u'maasserver.filestorage': {
134+ 'Meta': {'unique_together': "((u'filename', u'owner'),)", 'object_name': 'FileStorage'},
135+ 'content': ('metadataserver.fields.BinaryField', [], {'blank': 'True'}),
136+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
137+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
138+ 'key': ('django.db.models.fields.CharField', [], {'default': "u'c9791474-8d7b-11e3-8453-9c4e363b1c94'", 'unique': 'True', 'max_length': '36'}),
139+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
140+ },
141+ u'maasserver.macaddress': {
142+ 'Meta': {'object_name': 'MACAddress'},
143+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
144+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
145+ 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}),
146+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}),
147+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
148+ },
149+ u'maasserver.network': {
150+ 'Meta': {'object_name': 'Network'},
151+ 'description': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
152+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
153+ 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'unique': 'True', 'max_length': '39'}),
154+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
155+ 'netmask': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
156+ 'vlan_tag': ('django.db.models.fields.PositiveSmallIntegerField', [], {'unique': 'True'})
157+ },
158+ u'maasserver.node': {
159+ 'Meta': {'object_name': 'Node'},
160+ 'after_commissioning_action': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
161+ 'agent_name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
162+ 'architecture': ('django.db.models.fields.CharField', [], {'default': "u'i386/generic'", 'max_length': '31'}),
163+ 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
164+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
165+ 'distro_series': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'null': 'True', 'blank': 'True'}),
166+ 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
167+ 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'unique': 'True', 'max_length': '255', 'blank': 'True'}),
168+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
169+ 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
170+ 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
171+ 'networks': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Network']", 'symmetrical': 'False', 'blank': 'True'}),
172+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}),
173+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
174+ 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
175+ 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}),
176+ 'routers': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'macaddr'", 'null': 'True', 'blank': 'True'}),
177+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}),
178+ 'storage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
179+ 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-c97b5392-8d7b-11e3-8453-9c4e363b1c94'", 'unique': 'True', 'max_length': '41'}),
180+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}),
181+ 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'null': 'True'}),
182+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
183+ 'zone': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Zone']", 'on_delete': 'models.SET_DEFAULT'})
184+ },
185+ u'maasserver.nodegroup': {
186+ 'Meta': {'object_name': 'NodeGroup'},
187+ 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}),
188+ 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'unique': 'True'}),
189+ 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}),
190+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
191+ 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
192+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
193+ 'maas_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
194+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
195+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
196+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
197+ 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'})
198+ },
199+ u'maasserver.nodegroupinterface': {
200+ 'Meta': {'unique_together': "((u'nodegroup', u'interface'),)", 'object_name': 'NodeGroupInterface'},
201+ 'broadcast_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
202+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
203+ 'foreign_dhcp_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
204+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
205+ 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
206+ 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
207+ 'ip_range_high': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
208+ 'ip_range_low': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
209+ 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
210+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
211+ 'router_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
212+ 'subnet_mask': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
213+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
214+ },
215+ u'maasserver.sshkey': {
216+ 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'},
217+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
218+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
219+ 'key': ('django.db.models.fields.TextField', [], {}),
220+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
221+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
222+ },
223+ u'maasserver.tag': {
224+ 'Meta': {'object_name': 'Tag'},
225+ 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
226+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
227+ 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
228+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
229+ 'kernel_opts': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
230+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
231+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
232+ },
233+ u'maasserver.userprofile': {
234+ 'Meta': {'object_name': 'UserProfile'},
235+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
236+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
237+ },
238+ u'maasserver.zone': {
239+ 'Meta': {'ordering': "[u'name']", 'object_name': 'Zone'},
240+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
241+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
242+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
243+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
244+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
245+ },
246+ u'piston.consumer': {
247+ 'Meta': {'object_name': 'Consumer'},
248+ 'description': ('django.db.models.fields.TextField', [], {}),
249+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
250+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
251+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
252+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
253+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}),
254+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': u"orm['auth.User']"})
255+ },
256+ u'piston.token': {
257+ 'Meta': {'object_name': 'Token'},
258+ 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
259+ 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
260+ 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Consumer']"}),
261+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
262+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
263+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
264+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
265+ 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1391504854L'}),
266+ 'token_type': ('django.db.models.fields.IntegerField', [], {}),
267+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': u"orm['auth.User']"}),
268+ 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'})
269+ }
270+ }
271+
272+ complete_apps = ['maasserver']
273\ No newline at end of file
274
275=== removed file 'src/maasserver/migrations/0066_replace_vlan_with_network.py'
276--- src/maasserver/migrations/0066_replace_vlan_with_network.py 2014-02-04 02:53:33 +0000
277+++ src/maasserver/migrations/0066_replace_vlan_with_network.py 1970-01-01 00:00:00 +0000
278@@ -1,255 +0,0 @@
279-# -*- coding: utf-8 -*-
280-from south.utils import datetime_utils as datetime
281-from south.db import db
282-from south.v2 import SchemaMigration
283-from django.db import models
284-
285-
286-class Migration(SchemaMigration):
287-
288- def forwards(self, orm):
289- # Deleting model 'Vlan'
290- db.delete_table(u'maasserver_vlan')
291-
292- # Adding model 'Network'
293- db.create_table(u'maasserver_network', (
294- (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
295- ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
296- ('ip', self.gf('django.db.models.fields.GenericIPAddressField')(unique=True, max_length=39)),
297- ('netmask', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39)),
298- ('vlan_tag', self.gf('django.db.models.fields.PositiveSmallIntegerField')(unique=True)),
299- ('description', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, blank=True)),
300- ))
301- db.send_create_signal(u'maasserver', ['Network'])
302-
303-
304- def backwards(self, orm):
305- # Adding model 'Vlan'
306- db.create_table(u'maasserver_vlan', (
307- ('tag', self.gf('django.db.models.fields.PositiveSmallIntegerField')(unique=True)),
308- ('description', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, blank=True)),
309- (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
310- ))
311- db.send_create_signal(u'maasserver', ['Vlan'])
312-
313- # Deleting model 'Network'
314- db.delete_table(u'maasserver_network')
315-
316-
317- models = {
318- u'auth.group': {
319- 'Meta': {'object_name': 'Group'},
320- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
321- 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
322- 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
323- },
324- u'auth.permission': {
325- 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
326- 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
327- 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
328- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
329- 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
330- },
331- u'auth.user': {
332- 'Meta': {'object_name': 'User'},
333- 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
334- 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}),
335- 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
336- 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
337- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
338- 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
339- 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
340- 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
341- 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
342- 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
343- 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
344- 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
345- 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
346- },
347- u'contenttypes.contenttype': {
348- 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
349- 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
350- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
351- 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
352- 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
353- },
354- u'maasserver.bootimage': {
355- 'Meta': {'unique_together': "((u'nodegroup', u'architecture', u'subarchitecture', u'release', u'purpose'),)", 'object_name': 'BootImage'},
356- 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
357- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
358- 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
359- 'purpose': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
360- 'release': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
361- 'subarchitecture': ('django.db.models.fields.CharField', [], {'max_length': '255'})
362- },
363- u'maasserver.componenterror': {
364- 'Meta': {'object_name': 'ComponentError'},
365- 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
366- 'created': ('django.db.models.fields.DateTimeField', [], {}),
367- 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
368- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
369- 'updated': ('django.db.models.fields.DateTimeField', [], {})
370- },
371- u'maasserver.config': {
372- 'Meta': {'object_name': 'Config'},
373- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
374- 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
375- 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'})
376- },
377- u'maasserver.dhcplease': {
378- 'Meta': {'object_name': 'DHCPLease'},
379- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
380- 'ip': ('django.db.models.fields.IPAddressField', [], {'unique': 'True', 'max_length': '15'}),
381- 'mac': ('maasserver.fields.MACAddressField', [], {}),
382- 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"})
383- },
384- u'maasserver.downloadprogress': {
385- 'Meta': {'object_name': 'DownloadProgress'},
386- 'bytes_downloaded': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
387- 'created': ('django.db.models.fields.DateTimeField', [], {}),
388- 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}),
389- 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
390- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
391- 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
392- 'size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
393- 'updated': ('django.db.models.fields.DateTimeField', [], {})
394- },
395- u'maasserver.filestorage': {
396- 'Meta': {'unique_together': "((u'filename', u'owner'),)", 'object_name': 'FileStorage'},
397- 'content': ('metadataserver.fields.BinaryField', [], {'blank': 'True'}),
398- 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
399- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
400- 'key': ('django.db.models.fields.CharField', [], {'default': "u'707616c6-8d47-11e3-b9fc-94de80b61466'", 'unique': 'True', 'max_length': '36'}),
401- 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
402- },
403- u'maasserver.macaddress': {
404- 'Meta': {'object_name': 'MACAddress'},
405- 'created': ('django.db.models.fields.DateTimeField', [], {}),
406- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
407- 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}),
408- 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}),
409- 'updated': ('django.db.models.fields.DateTimeField', [], {})
410- },
411- u'maasserver.network': {
412- 'Meta': {'object_name': 'Network'},
413- 'description': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
414- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
415- 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'unique': 'True', 'max_length': '39'}),
416- 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
417- 'netmask': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
418- 'vlan_tag': ('django.db.models.fields.PositiveSmallIntegerField', [], {'unique': 'True'})
419- },
420- u'maasserver.node': {
421- 'Meta': {'object_name': 'Node'},
422- 'after_commissioning_action': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
423- 'agent_name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
424- 'architecture': ('django.db.models.fields.CharField', [], {'default': "u'i386/generic'", 'max_length': '31'}),
425- 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
426- 'created': ('django.db.models.fields.DateTimeField', [], {}),
427- 'distro_series': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'null': 'True', 'blank': 'True'}),
428- 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
429- 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'unique': 'True', 'max_length': '255', 'blank': 'True'}),
430- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
431- 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
432- 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
433- 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}),
434- 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
435- 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
436- 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}),
437- 'routers': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'macaddr'", 'null': 'True', 'blank': 'True'}),
438- 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}),
439- 'storage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
440- 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-7074e24c-8d47-11e3-b9fc-94de80b61466'", 'unique': 'True', 'max_length': '41'}),
441- 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}),
442- 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'null': 'True'}),
443- 'updated': ('django.db.models.fields.DateTimeField', [], {}),
444- 'zone': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Zone']", 'on_delete': 'models.SET_DEFAULT'})
445- },
446- u'maasserver.nodegroup': {
447- 'Meta': {'object_name': 'NodeGroup'},
448- 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}),
449- 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'unique': 'True'}),
450- 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}),
451- 'created': ('django.db.models.fields.DateTimeField', [], {}),
452- 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
453- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
454- 'maas_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
455- 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
456- 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
457- 'updated': ('django.db.models.fields.DateTimeField', [], {}),
458- 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'})
459- },
460- u'maasserver.nodegroupinterface': {
461- 'Meta': {'unique_together': "((u'nodegroup', u'interface'),)", 'object_name': 'NodeGroupInterface'},
462- 'broadcast_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
463- 'created': ('django.db.models.fields.DateTimeField', [], {}),
464- 'foreign_dhcp_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
465- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
466- 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
467- 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
468- 'ip_range_high': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
469- 'ip_range_low': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
470- 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
471- 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
472- 'router_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
473- 'subnet_mask': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
474- 'updated': ('django.db.models.fields.DateTimeField', [], {})
475- },
476- u'maasserver.sshkey': {
477- 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'},
478- 'created': ('django.db.models.fields.DateTimeField', [], {}),
479- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
480- 'key': ('django.db.models.fields.TextField', [], {}),
481- 'updated': ('django.db.models.fields.DateTimeField', [], {}),
482- 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
483- },
484- u'maasserver.tag': {
485- 'Meta': {'object_name': 'Tag'},
486- 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
487- 'created': ('django.db.models.fields.DateTimeField', [], {}),
488- 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
489- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
490- 'kernel_opts': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
491- 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
492- 'updated': ('django.db.models.fields.DateTimeField', [], {})
493- },
494- u'maasserver.userprofile': {
495- 'Meta': {'object_name': 'UserProfile'},
496- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
497- 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
498- },
499- u'maasserver.zone': {
500- 'Meta': {'ordering': "[u'name']", 'object_name': 'Zone'},
501- 'created': ('django.db.models.fields.DateTimeField', [], {}),
502- 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
503- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
504- 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
505- 'updated': ('django.db.models.fields.DateTimeField', [], {})
506- },
507- u'piston.consumer': {
508- 'Meta': {'object_name': 'Consumer'},
509- 'description': ('django.db.models.fields.TextField', [], {}),
510- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
511- 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
512- 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
513- 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
514- 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}),
515- 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': u"orm['auth.User']"})
516- },
517- u'piston.token': {
518- 'Meta': {'object_name': 'Token'},
519- 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
520- 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
521- 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Consumer']"}),
522- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
523- 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
524- 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
525- 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
526- 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1391482371L'}),
527- 'token_type': ('django.db.models.fields.IntegerField', [], {}),
528- 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': u"orm['auth.User']"}),
529- 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'})
530- }
531- }
532-
533- complete_apps = ['maasserver']
534\ No newline at end of file
535
536=== modified file 'src/maasserver/models/node.py'
537--- src/maasserver/models/node.py 2014-01-31 15:12:20 +0000
538+++ src/maasserver/models/node.py 2014-02-04 09:09:30 +0000
539@@ -64,6 +64,7 @@
540 JSONObjectField,
541 MAC,
542 )
543+from maasserver.models import Network
544 from maasserver.models.cleansave import CleanSave
545 from maasserver.models.config import Config
546 from maasserver.models.dhcplease import DHCPLease
547@@ -488,6 +489,8 @@
548
549 netboot = BooleanField(default=True)
550
551+ networks = ManyToManyField(Network, blank=True)
552+
553 # This field can't be null, but we can't enforce that in the
554 # database schema because we can only create the default value from
555 # a complete schema, after schema migration. We can't use custom
556
557=== modified file 'src/maasserver/models/tests/test_node.py'
558--- src/maasserver/models/tests/test_node.py 2014-02-01 05:54:22 +0000
559+++ src/maasserver/models/tests/test_node.py 2014-02-04 09:09:30 +0000
560@@ -1166,3 +1166,14 @@
561 node = factory.make_node(netboot=True)
562 node.set_netboot(False)
563 self.assertFalse(node.netboot)
564+
565+ def test_node_not_in_any_network_by_default(self):
566+ node = factory.make_node()
567+ self.assertItemsEqual([], node.networks.all())
568+
569+ def test_node_can_be_multiple_networks(self):
570+ node = factory.make_node()
571+ networks = [
572+ factory.make_network() for i in range(3)]
573+ node.networks.add(*networks)
574+ self.assertItemsEqual(networks, reload_object(node).networks.all())