Merge lp:~rvb/maas/add-vlan-fabric into lp:~maas-committers/maas/trunk
- add-vlan-fabric
- 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: | 4015 |
Proposed branch: | lp:~rvb/maas/add-vlan-fabric |
Merge into: | lp:~maas-committers/maas/trunk |
Diff against target: |
965 lines (+879/-2) 7 files modified
src/maasserver/migrations/0139_add_vlan_fabric.py (+494/-0) src/maasserver/models/__init__.py (+5/-2) src/maasserver/models/fabric.py (+113/-0) src/maasserver/models/tests/test_fabric.py (+85/-0) src/maasserver/models/tests/test_vlan.py (+79/-0) src/maasserver/models/vlan.py (+81/-0) src/maasserver/testing/factory.py (+22/-0) |
To merge this branch: | bzr merge lp:~rvb/maas/add-vlan-fabric |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email: mp+261693@code.launchpad.net |
Commit message
Add VLAN and Fabric models.
Description of the change
These models are only connect to each other right now. Connections to the new Interface model and the ClusterInterface model will be added in separate branches.
To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote : | # |
A few comments.
Revision history for this message
Mike Pontillo (mpontillo) wrote : | # |
Minor clarification.
Revision history for this message
Raphaël Badin (rvb) : | # |
Revision history for this message
Gavin Panella (allenap) wrote : | # |
Thanks for all your replies. Looks good, +1.
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/0139_add_vlan_fabric.py' | |||
2 | --- src/maasserver/migrations/0139_add_vlan_fabric.py 1970-01-01 00:00:00 +0000 | |||
3 | +++ src/maasserver/migrations/0139_add_vlan_fabric.py 2015-06-11 14:44:57 +0000 | |||
4 | @@ -0,0 +1,494 @@ | |||
5 | 1 | from django.db import models | ||
6 | 2 | from south.db import db | ||
7 | 3 | # -*- coding: utf-8 -*- | ||
8 | 4 | from south.utils import datetime_utils as datetime | ||
9 | 5 | from south.v2 import SchemaMigration | ||
10 | 6 | |||
11 | 7 | |||
12 | 8 | class Migration(SchemaMigration): | ||
13 | 9 | |||
14 | 10 | def forwards(self, orm): | ||
15 | 11 | # Adding model 'VLAN' | ||
16 | 12 | db.create_table(u'maasserver_vlan', ( | ||
17 | 13 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), | ||
18 | 14 | ('created', self.gf('django.db.models.fields.DateTimeField')()), | ||
19 | 15 | ('updated', self.gf('django.db.models.fields.DateTimeField')()), | ||
20 | 16 | ('name', self.gf('django.db.models.fields.CharField')(max_length=256)), | ||
21 | 17 | ('vid', self.gf('django.db.models.fields.IntegerField')()), | ||
22 | 18 | ('fabric', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['maasserver.Fabric'])), | ||
23 | 19 | )) | ||
24 | 20 | db.send_create_signal(u'maasserver', ['VLAN']) | ||
25 | 21 | |||
26 | 22 | # Adding unique constraint on 'VLAN', fields ['vid', 'fabric'] | ||
27 | 23 | db.create_unique(u'maasserver_vlan', ['vid', 'fabric_id']) | ||
28 | 24 | |||
29 | 25 | # Adding unique constraint on 'VLAN', fields ['name', 'fabric'] | ||
30 | 26 | db.create_unique(u'maasserver_vlan', ['name', 'fabric_id']) | ||
31 | 27 | |||
32 | 28 | # Adding model 'Fabric' | ||
33 | 29 | db.create_table(u'maasserver_fabric', ( | ||
34 | 30 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), | ||
35 | 31 | ('created', self.gf('django.db.models.fields.DateTimeField')()), | ||
36 | 32 | ('updated', self.gf('django.db.models.fields.DateTimeField')()), | ||
37 | 33 | ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=256)), | ||
38 | 34 | ('default_vlan', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name=u'+', null=True, to=orm['maasserver.VLAN'])), | ||
39 | 35 | )) | ||
40 | 36 | db.send_create_signal(u'maasserver', ['Fabric']) | ||
41 | 37 | |||
42 | 38 | |||
43 | 39 | def backwards(self, orm): | ||
44 | 40 | # Removing unique constraint on 'VLAN', fields ['name', 'fabric'] | ||
45 | 41 | db.delete_unique(u'maasserver_vlan', ['name', 'fabric_id']) | ||
46 | 42 | |||
47 | 43 | # Removing unique constraint on 'VLAN', fields ['vid', 'fabric'] | ||
48 | 44 | db.delete_unique(u'maasserver_vlan', ['vid', 'fabric_id']) | ||
49 | 45 | |||
50 | 46 | # Deleting model 'VLAN' | ||
51 | 47 | db.delete_table(u'maasserver_vlan') | ||
52 | 48 | |||
53 | 49 | # Deleting model 'Fabric' | ||
54 | 50 | db.delete_table(u'maasserver_fabric') | ||
55 | 51 | |||
56 | 52 | |||
57 | 53 | models = { | ||
58 | 54 | u'auth.group': { | ||
59 | 55 | 'Meta': {'object_name': 'Group'}, | ||
60 | 56 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
61 | 57 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
62 | 58 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
63 | 59 | }, | ||
64 | 60 | u'auth.permission': { | ||
65 | 61 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
66 | 62 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
67 | 63 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
68 | 64 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
69 | 65 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
70 | 66 | }, | ||
71 | 67 | u'auth.user': { | ||
72 | 68 | 'Meta': {'object_name': 'User'}, | ||
73 | 69 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
74 | 70 | 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
75 | 71 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
76 | 72 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
77 | 73 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
78 | 74 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
79 | 75 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
80 | 76 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
81 | 77 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
82 | 78 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
83 | 79 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
84 | 80 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
85 | 81 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | ||
86 | 82 | }, | ||
87 | 83 | u'contenttypes.contenttype': { | ||
88 | 84 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
89 | 85 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
90 | 86 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
91 | 87 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
92 | 88 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
93 | 89 | }, | ||
94 | 90 | u'maasserver.blockdevice': { | ||
95 | 91 | 'Meta': {'ordering': "[u'id']", 'unique_together': "((u'node', u'path'),)", 'object_name': 'BlockDevice'}, | ||
96 | 92 | 'block_size': ('django.db.models.fields.IntegerField', [], {}), | ||
97 | 93 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
98 | 94 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
99 | 95 | 'id_path': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), | ||
100 | 96 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
101 | 97 | 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}), | ||
102 | 98 | 'path': ('django.db.models.fields.FilePathField', [], {'max_length': '100'}), | ||
103 | 99 | 'size': ('django.db.models.fields.BigIntegerField', [], {}), | ||
104 | 100 | 'tags': ('djorm_pgarray.fields.ArrayField', [], {'default': '[]', 'dbtype': "u'text'", 'blank': 'True'}), | ||
105 | 101 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
106 | 102 | }, | ||
107 | 103 | u'maasserver.bootresource': { | ||
108 | 104 | 'Meta': {'unique_together': "((u'name', u'architecture'),)", 'object_name': 'BootResource'}, | ||
109 | 105 | 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
110 | 106 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
111 | 107 | 'extra': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}), | ||
112 | 108 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
113 | 109 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
114 | 110 | 'rtype': ('django.db.models.fields.IntegerField', [], {'max_length': '10'}), | ||
115 | 111 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
116 | 112 | }, | ||
117 | 113 | u'maasserver.bootresourcefile': { | ||
118 | 114 | 'Meta': {'unique_together': "((u'resource_set', u'filetype'),)", 'object_name': 'BootResourceFile'}, | ||
119 | 115 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
120 | 116 | 'extra': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}), | ||
121 | 117 | 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
122 | 118 | 'filetype': ('django.db.models.fields.CharField', [], {'default': "u'root-tgz'", 'max_length': '20'}), | ||
123 | 119 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
124 | 120 | 'largefile': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.LargeFile']"}), | ||
125 | 121 | 'resource_set': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'files'", 'to': u"orm['maasserver.BootResourceSet']"}), | ||
126 | 122 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
127 | 123 | }, | ||
128 | 124 | u'maasserver.bootresourceset': { | ||
129 | 125 | 'Meta': {'unique_together': "((u'resource', u'version'),)", 'object_name': 'BootResourceSet'}, | ||
130 | 126 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
131 | 127 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
132 | 128 | 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
133 | 129 | 'resource': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'sets'", 'to': u"orm['maasserver.BootResource']"}), | ||
134 | 130 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
135 | 131 | 'version': ('django.db.models.fields.CharField', [], {'max_length': '255'}) | ||
136 | 132 | }, | ||
137 | 133 | u'maasserver.bootsource': { | ||
138 | 134 | 'Meta': {'object_name': 'BootSource'}, | ||
139 | 135 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
140 | 136 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
141 | 137 | 'keyring_data': ('maasserver.fields.EditableBinaryField', [], {'blank': 'True'}), | ||
142 | 138 | 'keyring_filename': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}), | ||
143 | 139 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
144 | 140 | 'url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200'}) | ||
145 | 141 | }, | ||
146 | 142 | u'maasserver.bootsourcecache': { | ||
147 | 143 | 'Meta': {'object_name': 'BootSourceCache'}, | ||
148 | 144 | 'arch': ('django.db.models.fields.CharField', [], {'max_length': '20'}), | ||
149 | 145 | 'boot_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.BootSource']"}), | ||
150 | 146 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
151 | 147 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
152 | 148 | 'label': ('django.db.models.fields.CharField', [], {'max_length': '20'}), | ||
153 | 149 | 'os': ('django.db.models.fields.CharField', [], {'max_length': '20'}), | ||
154 | 150 | 'release': ('django.db.models.fields.CharField', [], {'max_length': '20'}), | ||
155 | 151 | 'subarch': ('django.db.models.fields.CharField', [], {'max_length': '20'}), | ||
156 | 152 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
157 | 153 | }, | ||
158 | 154 | u'maasserver.bootsourceselection': { | ||
159 | 155 | 'Meta': {'unique_together': "((u'boot_source', u'os', u'release'),)", 'object_name': 'BootSourceSelection'}, | ||
160 | 156 | 'arches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
161 | 157 | 'boot_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.BootSource']"}), | ||
162 | 158 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
163 | 159 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
164 | 160 | 'labels': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
165 | 161 | 'os': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
166 | 162 | 'release': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
167 | 163 | 'subarches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
168 | 164 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
169 | 165 | }, | ||
170 | 166 | u'maasserver.candidatename': { | ||
171 | 167 | 'Meta': {'unique_together': "((u'name', u'position'),)", 'object_name': 'CandidateName'}, | ||
172 | 168 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
173 | 169 | 'name': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), | ||
174 | 170 | 'position': ('django.db.models.fields.IntegerField', [], {}) | ||
175 | 171 | }, | ||
176 | 172 | u'maasserver.componenterror': { | ||
177 | 173 | 'Meta': {'object_name': 'ComponentError'}, | ||
178 | 174 | 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}), | ||
179 | 175 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
180 | 176 | 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}), | ||
181 | 177 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
182 | 178 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
183 | 179 | }, | ||
184 | 180 | u'maasserver.config': { | ||
185 | 181 | 'Meta': {'object_name': 'Config'}, | ||
186 | 182 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
187 | 183 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), | ||
188 | 184 | 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'}) | ||
189 | 185 | }, | ||
190 | 186 | u'maasserver.dhcplease': { | ||
191 | 187 | 'Meta': {'object_name': 'DHCPLease'}, | ||
192 | 188 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
193 | 189 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
194 | 190 | 'mac': ('maasserver.fields.MACAddressField', [], {}), | ||
195 | 191 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}) | ||
196 | 192 | }, | ||
197 | 193 | u'maasserver.downloadprogress': { | ||
198 | 194 | 'Meta': {'object_name': 'DownloadProgress'}, | ||
199 | 195 | 'bytes_downloaded': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), | ||
200 | 196 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
201 | 197 | 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}), | ||
202 | 198 | 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
203 | 199 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
204 | 200 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
205 | 201 | 'size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), | ||
206 | 202 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
207 | 203 | }, | ||
208 | 204 | u'maasserver.event': { | ||
209 | 205 | 'Meta': {'object_name': 'Event'}, | ||
210 | 206 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
211 | 207 | 'description': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}), | ||
212 | 208 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
213 | 209 | 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}), | ||
214 | 210 | 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.EventType']"}), | ||
215 | 211 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
216 | 212 | }, | ||
217 | 213 | u'maasserver.eventtype': { | ||
218 | 214 | 'Meta': {'object_name': 'EventType'}, | ||
219 | 215 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
220 | 216 | 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
221 | 217 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
222 | 218 | 'level': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), | ||
223 | 219 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), | ||
224 | 220 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
225 | 221 | }, | ||
226 | 222 | u'maasserver.fabric': { | ||
227 | 223 | 'Meta': {'object_name': 'Fabric'}, | ||
228 | 224 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
229 | 225 | 'default_vlan': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'+'", 'null': 'True', 'to': u"orm['maasserver.VLAN']"}), | ||
230 | 226 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
231 | 227 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}), | ||
232 | 228 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
233 | 229 | }, | ||
234 | 230 | u'maasserver.filestorage': { | ||
235 | 231 | 'Meta': {'unique_together': "((u'filename', u'owner'),)", 'object_name': 'FileStorage'}, | ||
236 | 232 | 'content': ('metadataserver.fields.BinaryField', [], {'blank': 'True'}), | ||
237 | 233 | 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
238 | 234 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
239 | 235 | 'key': ('django.db.models.fields.CharField', [], {'default': "u'4bab59ce-1017-11e5-9b34-3c970e0e56dc'", 'unique': 'True', 'max_length': '36'}), | ||
240 | 236 | 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) | ||
241 | 237 | }, | ||
242 | 238 | u'maasserver.filesystem': { | ||
243 | 239 | 'Meta': {'object_name': 'Filesystem'}, | ||
244 | 240 | 'block_device': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.BlockDevice']", 'null': 'True', 'blank': 'True'}), | ||
245 | 241 | 'create_params': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
246 | 242 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
247 | 243 | 'filesystem_group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'filesystems'", 'null': 'True', 'to': u"orm['maasserver.FilesystemGroup']"}), | ||
248 | 244 | 'fstype': ('django.db.models.fields.CharField', [], {'default': "u'ext4'", 'max_length': '20'}), | ||
249 | 245 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
250 | 246 | 'mount_params': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
251 | 247 | 'mount_point': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
252 | 248 | 'partition': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Partition']", 'null': 'True', 'blank': 'True'}), | ||
253 | 249 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
254 | 250 | 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}) | ||
255 | 251 | }, | ||
256 | 252 | u'maasserver.filesystemgroup': { | ||
257 | 253 | 'Meta': {'object_name': 'FilesystemGroup'}, | ||
258 | 254 | 'create_params': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
259 | 255 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
260 | 256 | 'group_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}), | ||
261 | 257 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
262 | 258 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
263 | 259 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
264 | 260 | 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}) | ||
265 | 261 | }, | ||
266 | 262 | u'maasserver.largefile': { | ||
267 | 263 | 'Meta': {'object_name': 'LargeFile'}, | ||
268 | 264 | 'content': ('maasserver.fields.LargeObjectField', [], {}), | ||
269 | 265 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
270 | 266 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
271 | 267 | 'sha256': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}), | ||
272 | 268 | 'total_size': ('django.db.models.fields.BigIntegerField', [], {}), | ||
273 | 269 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
274 | 270 | }, | ||
275 | 271 | u'maasserver.licensekey': { | ||
276 | 272 | 'Meta': {'unique_together': "((u'osystem', u'distro_series'),)", 'object_name': 'LicenseKey'}, | ||
277 | 273 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
278 | 274 | 'distro_series': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
279 | 275 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
280 | 276 | 'license_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
281 | 277 | 'osystem': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
282 | 278 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
283 | 279 | }, | ||
284 | 280 | u'maasserver.macaddress': { | ||
285 | 281 | 'Meta': {'ordering': "(u'created',)", 'object_name': 'MACAddress'}, | ||
286 | 282 | 'cluster_interface': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['maasserver.NodeGroupInterface']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), | ||
287 | 283 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
288 | 284 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
289 | 285 | 'ip_addresses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.StaticIPAddress']", 'symmetrical': 'False', 'through': u"orm['maasserver.MACStaticIPAddressLink']", 'blank': 'True'}), | ||
290 | 286 | 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}), | ||
291 | 287 | 'networks': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Network']", 'symmetrical': 'False', 'blank': 'True'}), | ||
292 | 288 | 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']", 'null': 'True', 'blank': 'True'}), | ||
293 | 289 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
294 | 290 | }, | ||
295 | 291 | u'maasserver.macstaticipaddresslink': { | ||
296 | 292 | 'Meta': {'unique_together': "((u'ip_address', u'mac_address'),)", 'object_name': 'MACStaticIPAddressLink'}, | ||
297 | 293 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
298 | 294 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
299 | 295 | 'ip_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.StaticIPAddress']", 'unique': 'True'}), | ||
300 | 296 | 'mac_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.MACAddress']"}), | ||
301 | 297 | 'nic_alias': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), | ||
302 | 298 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
303 | 299 | }, | ||
304 | 300 | u'maasserver.network': { | ||
305 | 301 | 'Meta': {'object_name': 'Network'}, | ||
306 | 302 | 'default_gateway': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
307 | 303 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
308 | 304 | 'dns_servers': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
309 | 305 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
310 | 306 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
311 | 307 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), | ||
312 | 308 | 'netmask': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39'}), | ||
313 | 309 | 'vlan_tag': ('django.db.models.fields.PositiveSmallIntegerField', [], {'unique': 'True', 'null': 'True', 'blank': 'True'}) | ||
314 | 310 | }, | ||
315 | 311 | u'maasserver.node': { | ||
316 | 312 | 'Meta': {'object_name': 'Node'}, | ||
317 | 313 | 'agent_name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
318 | 314 | 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '31', 'null': 'True', 'blank': 'True'}), | ||
319 | 315 | 'boot_type': ('django.db.models.fields.CharField', [], {'default': "u'fastpath'", 'max_length': '20'}), | ||
320 | 316 | 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
321 | 317 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
322 | 318 | 'disable_ipv4': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
323 | 319 | 'distro_series': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
324 | 320 | 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
325 | 321 | 'error_description': ('django.db.models.fields.TextField', [], {'default': "u''", 'blank': 'True'}), | ||
326 | 322 | 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'unique': 'True', 'max_length': '255', 'blank': 'True'}), | ||
327 | 323 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
328 | 324 | 'installable': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}), | ||
329 | 325 | 'license_key': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), | ||
330 | 326 | 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
331 | 327 | 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
332 | 328 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}), | ||
333 | 329 | 'osystem': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
334 | 330 | 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), | ||
335 | 331 | 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "u'children'", 'null': 'True', 'blank': 'True', 'to': u"orm['maasserver.Node']"}), | ||
336 | 332 | 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}), | ||
337 | 333 | 'power_state': ('django.db.models.fields.CharField', [], {'default': "u'unknown'", 'max_length': '10'}), | ||
338 | 334 | 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}), | ||
339 | 335 | 'pxe_mac': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': u"orm['maasserver.MACAddress']", 'blank': 'True', 'null': 'True'}), | ||
340 | 336 | 'routers': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'macaddr'", 'null': 'True', 'blank': 'True'}), | ||
341 | 337 | 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}), | ||
342 | 338 | 'swap_size': ('django.db.models.fields.BigIntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), | ||
343 | 339 | 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-4bae813a-1017-11e5-9b34-3c970e0e56dc'", 'unique': 'True', 'max_length': '41'}), | ||
344 | 340 | 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}), | ||
345 | 341 | 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'null': 'True'}), | ||
346 | 342 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
347 | 343 | 'zone': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Zone']", 'on_delete': 'models.SET_DEFAULT'}) | ||
348 | 344 | }, | ||
349 | 345 | u'maasserver.nodegroup': { | ||
350 | 346 | 'Meta': {'object_name': 'NodeGroup'}, | ||
351 | 347 | 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}), | ||
352 | 348 | 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'unique': 'True'}), | ||
353 | 349 | 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}), | ||
354 | 350 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
355 | 351 | 'default_disable_ipv4': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
356 | 352 | 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
357 | 353 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
358 | 354 | 'maas_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
359 | 355 | 'name': ('maasserver.models.nodegroup.DomainNameField', [], {'max_length': '80', 'blank': 'True'}), | ||
360 | 356 | 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}), | ||
361 | 357 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
362 | 358 | 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}) | ||
363 | 359 | }, | ||
364 | 360 | u'maasserver.nodegroupinterface': { | ||
365 | 361 | 'Meta': {'unique_together': "((u'nodegroup', u'name'),)", 'object_name': 'NodeGroupInterface'}, | ||
366 | 362 | 'broadcast_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
367 | 363 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
368 | 364 | 'foreign_dhcp_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
369 | 365 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
370 | 366 | 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
371 | 367 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'max_length': '39'}), | ||
372 | 368 | 'ip_range_high': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
373 | 369 | 'ip_range_low': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
374 | 370 | 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
375 | 371 | 'name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
376 | 372 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
377 | 373 | 'router_ip': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
378 | 374 | 'static_ip_range_high': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
379 | 375 | 'static_ip_range_low': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
380 | 376 | 'subnet_mask': ('maasserver.fields.MAASIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
381 | 377 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
382 | 378 | }, | ||
383 | 379 | u'maasserver.partition': { | ||
384 | 380 | 'Meta': {'object_name': 'Partition'}, | ||
385 | 381 | 'bootable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
386 | 382 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
387 | 383 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
388 | 384 | 'partition_table': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'partitions'", 'to': u"orm['maasserver.PartitionTable']"}), | ||
389 | 385 | 'size': ('django.db.models.fields.BigIntegerField', [], {}), | ||
390 | 386 | 'start_offset': ('django.db.models.fields.BigIntegerField', [], {}), | ||
391 | 387 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
392 | 388 | 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '36', 'unique': 'True', 'null': 'True', 'blank': 'True'}) | ||
393 | 389 | }, | ||
394 | 390 | u'maasserver.partitiontable': { | ||
395 | 391 | 'Meta': {'object_name': 'PartitionTable'}, | ||
396 | 392 | 'block_device': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.BlockDevice']"}), | ||
397 | 393 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
398 | 394 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
399 | 395 | 'table_type': ('django.db.models.fields.CharField', [], {'default': "u'GPT'", 'max_length': '20'}), | ||
400 | 396 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
401 | 397 | }, | ||
402 | 398 | u'maasserver.physicalblockdevice': { | ||
403 | 399 | 'Meta': {'ordering': "[u'id']", 'object_name': 'PhysicalBlockDevice', '_ormbases': [u'maasserver.BlockDevice']}, | ||
404 | 400 | u'blockdevice_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['maasserver.BlockDevice']", 'unique': 'True', 'primary_key': 'True'}), | ||
405 | 401 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), | ||
406 | 402 | 'serial': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}) | ||
407 | 403 | }, | ||
408 | 404 | u'maasserver.sshkey': { | ||
409 | 405 | 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'}, | ||
410 | 406 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
411 | 407 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
412 | 408 | 'key': ('django.db.models.fields.TextField', [], {}), | ||
413 | 409 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
414 | 410 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) | ||
415 | 411 | }, | ||
416 | 412 | u'maasserver.sslkey': { | ||
417 | 413 | 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSLKey'}, | ||
418 | 414 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
419 | 415 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
420 | 416 | 'key': ('django.db.models.fields.TextField', [], {}), | ||
421 | 417 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
422 | 418 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) | ||
423 | 419 | }, | ||
424 | 420 | u'maasserver.staticipaddress': { | ||
425 | 421 | 'Meta': {'object_name': 'StaticIPAddress'}, | ||
426 | 422 | 'alloc_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
427 | 423 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
428 | 424 | 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
429 | 425 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
430 | 426 | 'ip': ('maasserver.fields.MAASIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
431 | 427 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
432 | 428 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) | ||
433 | 429 | }, | ||
434 | 430 | u'maasserver.tag': { | ||
435 | 431 | 'Meta': {'object_name': 'Tag'}, | ||
436 | 432 | 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
437 | 433 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
438 | 434 | 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
439 | 435 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
440 | 436 | 'kernel_opts': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), | ||
441 | 437 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}), | ||
442 | 438 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
443 | 439 | }, | ||
444 | 440 | u'maasserver.userprofile': { | ||
445 | 441 | 'Meta': {'object_name': 'UserProfile'}, | ||
446 | 442 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
447 | 443 | 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) | ||
448 | 444 | }, | ||
449 | 445 | u'maasserver.virtualblockdevice': { | ||
450 | 446 | 'Meta': {'ordering': "[u'id']", 'object_name': 'VirtualBlockDevice', '_ormbases': [u'maasserver.BlockDevice']}, | ||
451 | 447 | u'blockdevice_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['maasserver.BlockDevice']", 'unique': 'True', 'primary_key': 'True'}), | ||
452 | 448 | 'filesystem_group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'virtual_devices'", 'to': u"orm['maasserver.FilesystemGroup']"}), | ||
453 | 449 | 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}) | ||
454 | 450 | }, | ||
455 | 451 | u'maasserver.vlan': { | ||
456 | 452 | 'Meta': {'unique_together': "((u'vid', u'fabric'), (u'name', u'fabric'))", 'object_name': 'VLAN'}, | ||
457 | 453 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
458 | 454 | 'fabric': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Fabric']"}), | ||
459 | 455 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
460 | 456 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '256'}), | ||
461 | 457 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
462 | 458 | 'vid': ('django.db.models.fields.IntegerField', [], {}) | ||
463 | 459 | }, | ||
464 | 460 | u'maasserver.zone': { | ||
465 | 461 | 'Meta': {'ordering': "[u'name']", 'object_name': 'Zone'}, | ||
466 | 462 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
467 | 463 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
468 | 464 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
469 | 465 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}), | ||
470 | 466 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
471 | 467 | }, | ||
472 | 468 | u'piston.consumer': { | ||
473 | 469 | 'Meta': {'object_name': 'Consumer'}, | ||
474 | 470 | 'description': ('django.db.models.fields.TextField', [], {}), | ||
475 | 471 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
476 | 472 | 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}), | ||
477 | 473 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
478 | 474 | 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}), | ||
479 | 475 | 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}), | ||
480 | 476 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': u"orm['auth.User']"}) | ||
481 | 477 | }, | ||
482 | 478 | u'piston.token': { | ||
483 | 479 | 'Meta': {'object_name': 'Token'}, | ||
484 | 480 | 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
485 | 481 | 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
486 | 482 | 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Consumer']"}), | ||
487 | 483 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
488 | 484 | 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
489 | 485 | 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}), | ||
490 | 486 | 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}), | ||
491 | 487 | 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1434012793L'}), | ||
492 | 488 | 'token_type': ('django.db.models.fields.IntegerField', [], {}), | ||
493 | 489 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': u"orm['auth.User']"}), | ||
494 | 490 | 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'}) | ||
495 | 491 | } | ||
496 | 492 | } | ||
497 | 493 | |||
498 | 494 | complete_apps = ['maasserver'] | ||
499 | 0 | \ No newline at end of file | 495 | \ No newline at end of file |
500 | 1 | 496 | ||
501 | === modified file 'src/maasserver/models/__init__.py' | |||
502 | --- src/maasserver/models/__init__.py 2015-06-09 20:16:46 +0000 | |||
503 | +++ src/maasserver/models/__init__.py 2015-06-11 14:44:57 +0000 | |||
504 | @@ -29,6 +29,7 @@ | |||
505 | 29 | 'FileStorage', | 29 | 'FileStorage', |
506 | 30 | 'Filesystem', | 30 | 'Filesystem', |
507 | 31 | 'FilesystemGroup', | 31 | 'FilesystemGroup', |
508 | 32 | 'Interface', | ||
509 | 32 | 'LargeFile', | 33 | 'LargeFile', |
510 | 33 | 'LicenseKey', | 34 | 'LicenseKey', |
511 | 34 | 'logger', | 35 | 'logger', |
512 | @@ -72,6 +73,7 @@ | |||
513 | 72 | from maasserver.models.downloadprogress import DownloadProgress | 73 | from maasserver.models.downloadprogress import DownloadProgress |
514 | 73 | from maasserver.models.event import Event | 74 | from maasserver.models.event import Event |
515 | 74 | from maasserver.models.eventtype import EventType | 75 | from maasserver.models.eventtype import EventType |
516 | 76 | from maasserver.models.fabric import Fabric | ||
517 | 75 | from maasserver.models.filestorage import FileStorage | 77 | from maasserver.models.filestorage import FileStorage |
518 | 76 | from maasserver.models.filesystem import Filesystem | 78 | from maasserver.models.filesystem import Filesystem |
519 | 77 | from maasserver.models.filesystemgroup import FilesystemGroup | 79 | from maasserver.models.filesystemgroup import FilesystemGroup |
520 | @@ -96,6 +98,7 @@ | |||
521 | 96 | from maasserver.models.user import create_user | 98 | from maasserver.models.user import create_user |
522 | 97 | from maasserver.models.userprofile import UserProfile | 99 | from maasserver.models.userprofile import UserProfile |
523 | 98 | from maasserver.models.virtualblockdevice import VirtualBlockDevice | 100 | from maasserver.models.virtualblockdevice import VirtualBlockDevice |
524 | 101 | from maasserver.models.vlan import VLAN | ||
525 | 99 | from maasserver.models.zone import Zone | 102 | from maasserver.models.zone import Zone |
526 | 100 | from maasserver.utils import ignore_unused | 103 | from maasserver.utils import ignore_unused |
527 | 101 | from piston.doc import HandlerDocumentation | 104 | from piston.doc import HandlerDocumentation |
528 | @@ -105,10 +108,10 @@ | |||
529 | 105 | ignore_unused( | 108 | ignore_unused( |
530 | 106 | BootResource, BootResourceFile, BootResourceSet, CandidateName, | 109 | BootResource, BootResourceFile, BootResourceSet, CandidateName, |
531 | 107 | ComponentError, Config, DHCPLease, DownloadProgress, Event, EventType, | 110 | ComponentError, Config, DHCPLease, DownloadProgress, Event, EventType, |
533 | 108 | FileStorage, Filesystem, FilesystemGroup, LargeFile, LicenseKey, | 111 | Fabric, FileStorage, Filesystem, FilesystemGroup, LargeFile, LicenseKey, |
534 | 109 | StaticIPAddress, MACAddress, MACStaticIPAddressLink, Network, NodeGroup, | 112 | StaticIPAddress, MACAddress, MACStaticIPAddressLink, Network, NodeGroup, |
535 | 110 | NodeGroupInterface, Partition, PartitionTable, SSHKey, Tag, UserProfile, | 113 | NodeGroupInterface, Partition, PartitionTable, SSHKey, Tag, UserProfile, |
537 | 111 | VirtualBlockDevice, Zone, logger) | 114 | VirtualBlockDevice, VLAN, Zone, logger) |
538 | 112 | 115 | ||
539 | 113 | 116 | ||
540 | 114 | # Connect the 'create_user' method to the post save signal of User. | 117 | # Connect the 'create_user' method to the post save signal of User. |
541 | 115 | 118 | ||
542 | === added file 'src/maasserver/models/fabric.py' | |||
543 | --- src/maasserver/models/fabric.py 1970-01-01 00:00:00 +0000 | |||
544 | +++ src/maasserver/models/fabric.py 2015-06-11 14:44:57 +0000 | |||
545 | @@ -0,0 +1,113 @@ | |||
546 | 1 | # Copyright 2015 Canonical Ltd. This software is licensed under the | ||
547 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
548 | 3 | |||
549 | 4 | """Fabric objects.""" | ||
550 | 5 | |||
551 | 6 | from __future__ import ( | ||
552 | 7 | absolute_import, | ||
553 | 8 | print_function, | ||
554 | 9 | unicode_literals, | ||
555 | 10 | ) | ||
556 | 11 | |||
557 | 12 | str = None | ||
558 | 13 | |||
559 | 14 | __metaclass__ = type | ||
560 | 15 | __all__ = [ | ||
561 | 16 | "DEFAULT_FABRIC_NAME", | ||
562 | 17 | "Fabric", | ||
563 | 18 | "FABRIC_NAME_VALIDATOR", | ||
564 | 19 | ] | ||
565 | 20 | |||
566 | 21 | import datetime | ||
567 | 22 | |||
568 | 23 | from django.core.exceptions import ValidationError | ||
569 | 24 | from django.core.validators import RegexValidator | ||
570 | 25 | from django.db.models import ( | ||
571 | 26 | CharField, | ||
572 | 27 | ForeignKey, | ||
573 | 28 | Manager, | ||
574 | 29 | ) | ||
575 | 30 | from maasserver import DefaultMeta | ||
576 | 31 | from maasserver.models.cleansave import CleanSave | ||
577 | 32 | from maasserver.models.timestampedmodel import TimestampedModel | ||
578 | 33 | |||
579 | 34 | |||
580 | 35 | FABRIC_NAME_VALIDATOR = RegexValidator('^[ \w-]+$') | ||
581 | 36 | |||
582 | 37 | # Name of the special, default fabric. This fabric cannot be deleted. | ||
583 | 38 | DEFAULT_FABRIC_NAME = 'Default fabric' | ||
584 | 39 | |||
585 | 40 | |||
586 | 41 | class FabricManager(Manager): | ||
587 | 42 | """Manager for :class:`Fabric` model.""" | ||
588 | 43 | |||
589 | 44 | def get_default_fabric(self): | ||
590 | 45 | """Return the default fabric.""" | ||
591 | 46 | now = datetime.datetime.now() | ||
592 | 47 | fabric, _ = self.get_or_create( | ||
593 | 48 | id=0, | ||
594 | 49 | defaults={ | ||
595 | 50 | 'id': 0, | ||
596 | 51 | 'name': DEFAULT_FABRIC_NAME, | ||
597 | 52 | 'created': now, | ||
598 | 53 | 'updated': now, | ||
599 | 54 | } | ||
600 | 55 | ) | ||
601 | 56 | return fabric | ||
602 | 57 | |||
603 | 58 | |||
604 | 59 | class Fabric(CleanSave, TimestampedModel): | ||
605 | 60 | """A `Fabric`. | ||
606 | 61 | |||
607 | 62 | :ivar name: The short-human-identifiable name for this fabric. | ||
608 | 63 | :ivar objects: An instance of the class :class:`FabricManager`. | ||
609 | 64 | """ | ||
610 | 65 | |||
611 | 66 | class Meta(DefaultMeta): | ||
612 | 67 | """Needed for South to recognize this model.""" | ||
613 | 68 | verbose_name = "Fabric" | ||
614 | 69 | verbose_name_plural = "Fabrics" | ||
615 | 70 | |||
616 | 71 | objects = FabricManager() | ||
617 | 72 | |||
618 | 73 | name = CharField( | ||
619 | 74 | max_length=256, unique=True, editable=True, | ||
620 | 75 | validators=[FABRIC_NAME_VALIDATOR]) | ||
621 | 76 | |||
622 | 77 | default_vlan = ForeignKey( | ||
623 | 78 | 'VLAN', blank=True, null=True, editable=True, related_name='+') | ||
624 | 79 | |||
625 | 80 | def __unicode__(self): | ||
626 | 81 | return "name=%s" % self.name | ||
627 | 82 | |||
628 | 83 | def is_default(self): | ||
629 | 84 | """Is this the default fabric?""" | ||
630 | 85 | return self.id == 0 | ||
631 | 86 | |||
632 | 87 | def clean(self, *args, **kwargs): | ||
633 | 88 | wrong_fabric = ( | ||
634 | 89 | self.default_vlan_id is not None and | ||
635 | 90 | self.default_vlan.fabric != self) | ||
636 | 91 | if wrong_fabric: | ||
637 | 92 | raise ValidationError( | ||
638 | 93 | {'default_vlan': | ||
639 | 94 | ["Can't set a default VLAN that's not in this fabric."]}) | ||
640 | 95 | super(Fabric, self).clean(*args, **kwargs) | ||
641 | 96 | |||
642 | 97 | def delete(self): | ||
643 | 98 | if self.is_default(): | ||
644 | 99 | raise ValidationError( | ||
645 | 100 | "This fabric is the default fabric, it cannot be deleted.") | ||
646 | 101 | super(Fabric, self).delete() | ||
647 | 102 | |||
648 | 103 | def save(self, *args, **kwargs): | ||
649 | 104 | created = self.id is None | ||
650 | 105 | super(Fabric, self).save(*args, **kwargs) | ||
651 | 106 | # Create default VLAN if this is a fabric creation. | ||
652 | 107 | if created: | ||
653 | 108 | from maasserver.models.vlan import ( | ||
654 | 109 | VLAN, DEFAULT_VLAN_NAME, DEFAULT_VID) | ||
655 | 110 | default_vlan = VLAN.objects.create( | ||
656 | 111 | name=DEFAULT_VLAN_NAME, vid=DEFAULT_VID, fabric=self) | ||
657 | 112 | self.default_vlan = default_vlan | ||
658 | 113 | self.save() | ||
659 | 0 | 114 | ||
660 | === added file 'src/maasserver/models/tests/test_fabric.py' | |||
661 | --- src/maasserver/models/tests/test_fabric.py 1970-01-01 00:00:00 +0000 | |||
662 | +++ src/maasserver/models/tests/test_fabric.py 2015-06-11 14:44:57 +0000 | |||
663 | @@ -0,0 +1,85 @@ | |||
664 | 1 | # Copyright 2015 Canonical Ltd. This software is licensed under the | ||
665 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
666 | 3 | |||
667 | 4 | """Tests for the Fabric model.""" | ||
668 | 5 | |||
669 | 6 | from __future__ import ( | ||
670 | 7 | absolute_import, | ||
671 | 8 | print_function, | ||
672 | 9 | unicode_literals, | ||
673 | 10 | ) | ||
674 | 11 | |||
675 | 12 | str = None | ||
676 | 13 | |||
677 | 14 | __metaclass__ = type | ||
678 | 15 | __all__ = [] | ||
679 | 16 | |||
680 | 17 | |||
681 | 18 | from django.core.exceptions import ValidationError | ||
682 | 19 | from maasserver.models.fabric import ( | ||
683 | 20 | DEFAULT_FABRIC_NAME, | ||
684 | 21 | Fabric, | ||
685 | 22 | ) | ||
686 | 23 | from maasserver.models.vlan import ( | ||
687 | 24 | DEFAULT_VID, | ||
688 | 25 | DEFAULT_VLAN_NAME, | ||
689 | 26 | ) | ||
690 | 27 | from maasserver.testing.factory import factory | ||
691 | 28 | from maasserver.testing.testcase import MAASServerTestCase | ||
692 | 29 | from testtools.matchers import MatchesStructure | ||
693 | 30 | from testtools.testcase import ExpectedException | ||
694 | 31 | |||
695 | 32 | |||
696 | 33 | class FabricTest(MAASServerTestCase): | ||
697 | 34 | |||
698 | 35 | def test_creates_fabric_with_default_vlan(self): | ||
699 | 36 | name = factory.make_name('name') | ||
700 | 37 | fabric = factory.make_Fabric(name=name) | ||
701 | 38 | self.assertEqual(name, fabric.name) | ||
702 | 39 | default_vlan = fabric.default_vlan | ||
703 | 40 | self.assertThat(default_vlan, MatchesStructure.byEquality( | ||
704 | 41 | vid=DEFAULT_VID, name=DEFAULT_VLAN_NAME)) | ||
705 | 42 | |||
706 | 43 | def test_get_default_fabric_creates_default_fabric(self): | ||
707 | 44 | default_fabric = Fabric.objects.get_default_fabric() | ||
708 | 45 | self.assertThat(default_fabric, MatchesStructure.byEquality( | ||
709 | 46 | id=0, name=DEFAULT_FABRIC_NAME)) | ||
710 | 47 | |||
711 | 48 | def test_get_default_fabric_is_idempotent(self): | ||
712 | 49 | default_fabric = Fabric.objects.get_default_fabric() | ||
713 | 50 | default_fabric2 = Fabric.objects.get_default_fabric() | ||
714 | 51 | self.assertEqual(default_fabric.id, default_fabric2.id) | ||
715 | 52 | |||
716 | 53 | def test_is_default_detects_default_fabric(self): | ||
717 | 54 | default_fabric = Fabric.objects.get_default_fabric() | ||
718 | 55 | self.assertTrue(default_fabric.is_default()) | ||
719 | 56 | |||
720 | 57 | def test_is_default_detects_non_default_fabric(self): | ||
721 | 58 | name = factory.make_name('name') | ||
722 | 59 | fabric = factory.make_Fabric(name=name) | ||
723 | 60 | self.assertFalse(fabric.is_default()) | ||
724 | 61 | |||
725 | 62 | def test_cant_delete_default_fabric(self): | ||
726 | 63 | default_fabric = Fabric.objects.get_default_fabric() | ||
727 | 64 | with ExpectedException(ValidationError): | ||
728 | 65 | default_fabric.delete() | ||
729 | 66 | |||
730 | 67 | def test_can_delete_non_default_fabric(self): | ||
731 | 68 | name = factory.make_name('name') | ||
732 | 69 | fabric = factory.make_Fabric(name=name) | ||
733 | 70 | fabric.delete() | ||
734 | 71 | self.assertItemsEqual([], Fabric.objects.all()) | ||
735 | 72 | |||
736 | 73 | def test_save_rejects_default_vlan_not_in_fabric(self): | ||
737 | 74 | vlan = factory.make_VLAN() | ||
738 | 75 | fabric = factory.make_Fabric() | ||
739 | 76 | fabric.default_vlan = vlan | ||
740 | 77 | with ExpectedException(ValidationError): | ||
741 | 78 | fabric.save() | ||
742 | 79 | |||
743 | 80 | def test_save_accepts_default_vlan_in_fabric(self): | ||
744 | 81 | fabric = factory.make_Fabric() | ||
745 | 82 | vlan = factory.make_VLAN(fabric=fabric) | ||
746 | 83 | fabric.default_vlan = vlan | ||
747 | 84 | # No exception. | ||
748 | 85 | self.assertIsNone(fabric.save()) | ||
749 | 0 | 86 | ||
750 | === added file 'src/maasserver/models/tests/test_vlan.py' | |||
751 | --- src/maasserver/models/tests/test_vlan.py 1970-01-01 00:00:00 +0000 | |||
752 | +++ src/maasserver/models/tests/test_vlan.py 2015-06-11 14:44:57 +0000 | |||
753 | @@ -0,0 +1,79 @@ | |||
754 | 1 | # Copyright 2015 Canonical Ltd. This software is licensed under the | ||
755 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
756 | 3 | |||
757 | 4 | """Tests for the VLAN model.""" | ||
758 | 5 | |||
759 | 6 | from __future__ import ( | ||
760 | 7 | absolute_import, | ||
761 | 8 | print_function, | ||
762 | 9 | unicode_literals, | ||
763 | 10 | ) | ||
764 | 11 | |||
765 | 12 | str = None | ||
766 | 13 | |||
767 | 14 | __metaclass__ = type | ||
768 | 15 | __all__ = [] | ||
769 | 16 | |||
770 | 17 | import random | ||
771 | 18 | |||
772 | 19 | from django.core.exceptions import ValidationError | ||
773 | 20 | from maasserver.models.vlan import VLAN | ||
774 | 21 | from maasserver.testing.factory import factory | ||
775 | 22 | from maasserver.testing.testcase import MAASServerTestCase | ||
776 | 23 | from testtools.matchers import MatchesStructure | ||
777 | 24 | from testtools.testcase import ExpectedException | ||
778 | 25 | |||
779 | 26 | |||
780 | 27 | class VLANTest(MAASServerTestCase): | ||
781 | 28 | |||
782 | 29 | def test_creates_vlan(self): | ||
783 | 30 | name = factory.make_name('name') | ||
784 | 31 | vid = random.randint(3, 55) | ||
785 | 32 | fabric = factory.make_Fabric() | ||
786 | 33 | vlan = VLAN(vid=vid, name=name, fabric=fabric) | ||
787 | 34 | vlan.save() | ||
788 | 35 | self.assertThat(vlan, MatchesStructure.byEquality( | ||
789 | 36 | vid=vid, name=name)) | ||
790 | 37 | |||
791 | 38 | def test_is_fabric_default_detects_default_vlan(self): | ||
792 | 39 | fabric = factory.make_Fabric() | ||
793 | 40 | vlan = factory.make_VLAN(fabric=fabric) | ||
794 | 41 | fabric.default_vlan = vlan | ||
795 | 42 | fabric.save() | ||
796 | 43 | self.assertTrue(vlan.is_fabric_default()) | ||
797 | 44 | |||
798 | 45 | def test_is_fabric_default_detects_non_default_vlan(self): | ||
799 | 46 | vlan = factory.make_VLAN() | ||
800 | 47 | self.assertFalse(vlan.is_fabric_default()) | ||
801 | 48 | |||
802 | 49 | |||
803 | 50 | class VLANVidValidationTest(MAASServerTestCase): | ||
804 | 51 | |||
805 | 52 | scenarios = [ | ||
806 | 53 | ('0', {'vid': 0, 'valid': True}), | ||
807 | 54 | ('12', {'vid': 12, 'valid': True}), | ||
808 | 55 | ('250', {'vid': 250, 'valid': True}), | ||
809 | 56 | ('3000', {'vid': 3000, 'valid': True}), | ||
810 | 57 | ('4095', {'vid': 4095, 'valid': True}), | ||
811 | 58 | ('-23', {'vid': -23, 'valid': False}), | ||
812 | 59 | ('4096', {'vid': 4096, 'valid': False}), | ||
813 | 60 | ('10000', {'vid': 10000, 'valid': False}), | ||
814 | 61 | ] | ||
815 | 62 | |||
816 | 63 | def test_validates_vid(self): | ||
817 | 64 | fabric = factory.make_Fabric() | ||
818 | 65 | # Remove the auto-created default VLAN so that | ||
819 | 66 | # we can create it in this test. | ||
820 | 67 | default_vlan = fabric.default_vlan | ||
821 | 68 | fabric.default_vlan = None | ||
822 | 69 | fabric.save() | ||
823 | 70 | default_vlan.delete() | ||
824 | 71 | name = factory.make_name('name') | ||
825 | 72 | vlan = VLAN(vid=self.vid, name=name, fabric=fabric) | ||
826 | 73 | if self.valid: | ||
827 | 74 | # No exception. | ||
828 | 75 | self.assertIsNone(vlan.save()) | ||
829 | 76 | |||
830 | 77 | else: | ||
831 | 78 | with ExpectedException(ValidationError): | ||
832 | 79 | vlan.save() | ||
833 | 0 | 80 | ||
834 | === added file 'src/maasserver/models/vlan.py' | |||
835 | --- src/maasserver/models/vlan.py 1970-01-01 00:00:00 +0000 | |||
836 | +++ src/maasserver/models/vlan.py 2015-06-11 14:44:57 +0000 | |||
837 | @@ -0,0 +1,81 @@ | |||
838 | 1 | # Copyright 2015 Canonical Ltd. This software is licensed under the | ||
839 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
840 | 3 | |||
841 | 4 | """VLAN objects.""" | ||
842 | 5 | |||
843 | 6 | from __future__ import ( | ||
844 | 7 | absolute_import, | ||
845 | 8 | print_function, | ||
846 | 9 | unicode_literals, | ||
847 | 10 | ) | ||
848 | 11 | |||
849 | 12 | str = None | ||
850 | 13 | |||
851 | 14 | __metaclass__ = type | ||
852 | 15 | __all__ = [ | ||
853 | 16 | "DEFAULT_VID", | ||
854 | 17 | "DEFAULT_VLAN_NAME", | ||
855 | 18 | "Fabric", | ||
856 | 19 | ] | ||
857 | 20 | |||
858 | 21 | |||
859 | 22 | from django.core.exceptions import ValidationError | ||
860 | 23 | from django.core.validators import RegexValidator | ||
861 | 24 | from django.db.models import ( | ||
862 | 25 | CharField, | ||
863 | 26 | ForeignKey, | ||
864 | 27 | IntegerField, | ||
865 | 28 | ) | ||
866 | 29 | from maasserver import DefaultMeta | ||
867 | 30 | from maasserver.models.cleansave import CleanSave | ||
868 | 31 | from maasserver.models.fabric import Fabric | ||
869 | 32 | from maasserver.models.timestampedmodel import TimestampedModel | ||
870 | 33 | |||
871 | 34 | |||
872 | 35 | VLAN_NAME_VALIDATOR = RegexValidator('^[ \w-]+$') | ||
873 | 36 | |||
874 | 37 | DEFAULT_VLAN_NAME = 'Default VLAN' | ||
875 | 38 | DEFAULT_VID = 0 | ||
876 | 39 | |||
877 | 40 | |||
878 | 41 | class VLAN(CleanSave, TimestampedModel): | ||
879 | 42 | """A `VLAN`. | ||
880 | 43 | |||
881 | 44 | :ivar name: The short-human-identifiable name for this VLAN. | ||
882 | 45 | :ivar vid: The VLAN ID of this VLAN. | ||
883 | 46 | :ivar fabric: The `Fabric` this VLAN belongs to. | ||
884 | 47 | """ | ||
885 | 48 | |||
886 | 49 | class Meta(DefaultMeta): | ||
887 | 50 | """Needed for South to recognize this model.""" | ||
888 | 51 | verbose_name = "VLAN" | ||
889 | 52 | verbose_name_plural = "VLANs" | ||
890 | 53 | unique_together = ( | ||
891 | 54 | ('vid', 'fabric'), | ||
892 | 55 | ('name', 'fabric'), | ||
893 | 56 | ) | ||
894 | 57 | |||
895 | 58 | name = CharField( | ||
896 | 59 | max_length=256, editable=True, validators=[VLAN_NAME_VALIDATOR]) | ||
897 | 60 | |||
898 | 61 | vid = IntegerField(editable=True) | ||
899 | 62 | |||
900 | 63 | fabric = ForeignKey( | ||
901 | 64 | 'Fabric', blank=False, editable=True) | ||
902 | 65 | |||
903 | 66 | def __unicode__(self): | ||
904 | 67 | return "name=%s, vid=%d, fabric=%s" % ( | ||
905 | 68 | self.name, self.vid, self.fabric.name) | ||
906 | 69 | |||
907 | 70 | def clean_vid(self): | ||
908 | 71 | if self.vid < 0 or self.vid > 4095: | ||
909 | 72 | raise ValidationError( | ||
910 | 73 | {'vid': | ||
911 | 74 | ["Vid must be between 0 and 4095."]}) | ||
912 | 75 | |||
913 | 76 | def clean(self): | ||
914 | 77 | self.clean_vid() | ||
915 | 78 | |||
916 | 79 | def is_fabric_default(self): | ||
917 | 80 | """Is this the default VLAN in the fabric?""" | ||
918 | 81 | return self.fabric.default_vlan == self | ||
919 | 0 | 82 | ||
920 | === modified file 'src/maasserver/testing/factory.py' | |||
921 | --- src/maasserver/testing/factory.py 2015-05-20 13:51:49 +0000 | |||
922 | +++ src/maasserver/testing/factory.py 2015-06-11 14:44:57 +0000 | |||
923 | @@ -56,6 +56,7 @@ | |||
924 | 56 | DownloadProgress, | 56 | DownloadProgress, |
925 | 57 | Event, | 57 | Event, |
926 | 58 | EventType, | 58 | EventType, |
927 | 59 | Fabric, | ||
928 | 59 | FileStorage, | 60 | FileStorage, |
929 | 60 | Filesystem, | 61 | Filesystem, |
930 | 61 | FilesystemGroup, | 62 | FilesystemGroup, |
931 | @@ -75,6 +76,7 @@ | |||
932 | 75 | StaticIPAddress, | 76 | StaticIPAddress, |
933 | 76 | Tag, | 77 | Tag, |
934 | 77 | VirtualBlockDevice, | 78 | VirtualBlockDevice, |
935 | 79 | VLAN, | ||
936 | 78 | Zone, | 80 | Zone, |
937 | 79 | ) | 81 | ) |
938 | 80 | from maasserver.models.bootresourceset import ( | 82 | from maasserver.models.bootresourceset import ( |
939 | @@ -581,6 +583,26 @@ | |||
940 | 581 | key.save() | 583 | key.save() |
941 | 582 | return key | 584 | return key |
942 | 583 | 585 | ||
943 | 586 | def make_Fabric(self, name=None): | ||
944 | 587 | if name is None: | ||
945 | 588 | name = self.make_name('fabric') | ||
946 | 589 | fabric = Fabric(name=name) | ||
947 | 590 | fabric.save() | ||
948 | 591 | return fabric | ||
949 | 592 | |||
950 | 593 | def make_VLAN(self, name=None, vid=None, fabric=None): | ||
951 | 594 | assert vid != 0, "VID=0 VLANs are auto-created" | ||
952 | 595 | if name is None: | ||
953 | 596 | name = self.make_name('vlan') | ||
954 | 597 | if vid is None: | ||
955 | 598 | # Don't create the vid=0 VLAN, it's auto-created. | ||
956 | 599 | vid = random.randint(1, 4095) | ||
957 | 600 | if fabric is None: | ||
958 | 601 | fabric = self.make_Fabric() | ||
959 | 602 | vlan = VLAN(name=name, vid=vid, fabric=fabric) | ||
960 | 603 | vlan.save() | ||
961 | 604 | return vlan | ||
962 | 605 | |||
963 | 584 | def make_Tag(self, name=None, definition=None, comment='', | 606 | def make_Tag(self, name=None, definition=None, comment='', |
964 | 585 | kernel_opts=None, created=None, updated=None): | 607 | kernel_opts=None, created=None, updated=None): |
965 | 586 | if name is None: | 608 | if name is None: |
Lots of questions!