Merge lp:~julian-edwards/maas/models-for-static-dhcp into lp:~maas-committers/maas/trunk
- models-for-static-dhcp
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Julian Edwards | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 2390 | ||||
Proposed branch: | lp:~julian-edwards/maas/models-for-static-dhcp | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Diff against target: |
527 lines (+454/-2) 7 files modified
src/maasserver/enum.py (+16/-0) src/maasserver/migrations/0081_ipaddress_table_and_static_dhcp_ranges.py (+326/-0) src/maasserver/models/__init__.py (+5/-2) src/maasserver/models/ipaddress.py (+53/-0) src/maasserver/models/macaddress.py (+6/-0) src/maasserver/models/macipaddresslink.py (+44/-0) src/maasserver/models/nodegroupinterface.py (+4/-0) |
||||
To merge this branch: | bzr merge lp:~julian-edwards/maas/models-for-static-dhcp | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeroen T. Vermeulen (community) | Approve | ||
Review via email:
|
Commit message
New model "IPAddress" and static IP range fields on nodegroupinterface. This is to prepare the way for a static host dhcpd declaration that does not intersect with the dynamic range.
Description of the change
Essentially, this is just introducing a new table to store static ip addresses, but is done in such a way to support the future changes described in that doc that we also need.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Julian Edwards (julian-edwards) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Julian Edwards (julian-edwards) wrote : | # |
I've made the IPAddress.
Additionally, we should note that there is no sensible migration you can do to create a static range for DHCP, it requires admin intervention. The simplest thing to do is if there is no static range defined, then continue as before with only dynamic leases. But this will come later in some actual code!
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jeroen T. Vermeulen (jtv) wrote : | # |
Please document IPAddress. It's really a static IP address, not just any dynamic-or-static IP address, right?
Why the foreign key from IPAddress to MACAddress in the first place? Wasn't that going to be a many-to-many relationship? Or is this transitional?
I'm not holding this up with my vote — whatever comes out, no harm done at this stage. Better to land and improve than to fork and languish. But to me, the "type" field affects the behaviour of the foreign key in too profound a way.
The biggest difference I see between the four types of relationship is what happens when a node is deallocated. If an IPAddress is "auto" or "extra," it goes down with the ship. If it's "unmanaged" or "sticky," it survives. I think those are different structural relationships, so maybe they should be two alternative foreign keys, with different cascading behaviours.
Of course my "biggest difference" only gets us to 2 types, out of 4. What are the other differences? It seems to me that:
* "Auto" is like "extra" except it can't be deallocated separately. Could be a separate relationship, or just a boolean attribute.
* "Unmanaged" is like "sticky" except the machine on the other end is not a node. But does that matter beyond creation and display? If you set an IP address for a machine's MAC address, then registered that machine as a node, ISTM the IP address would implicitly go from "unmanaged" to "sticky" without affecting the world in any way.
There may also be cardinality differences. I can't imagine attaching two MACs to the same "auto" address, but it might make sense for "extra" addresses. Splitting out the relationships may make the rules clearer, and easier to enforce as constraints.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Julian Edwards (julian-edwards) wrote : | # |
Thanks for reviewing jtv.
On 01/06/14 23:14, Jeroen T. Vermeulen wrote:
> Review: Approve
>
> Please document IPAddress. It's really a static IP address, not just any dynamic-or-static IP address, right?
Woops, I had meant to do that and forgot. I've expanded the docstring
now, thanks for spotting!
> Why the foreign key from IPAddress to MACAddress in the first place? Wasn't that going to be a many-to-many relationship? Or is this transitional?
See the maas-devel thread for gory details, but the upshot is that we
potentially need to have many IPs per MAC (VLANs, NIC aliases etc), but
we don't need to model many MACs per IP (VIPs) as we'll do that by
having a per-user IP.
> I'm not holding this up with my vote — whatever comes out, no harm done at this stage. Better to land and improve than to fork and languish. But to me, the "type" field affects the behaviour of the foreign key in too profound a way.
>
> The biggest difference I see between the four types of relationship is what happens when a node is deallocated. If an IPAddress is "auto" or "extra," it goes down with the ship. If it's "unmanaged" or "sticky," it survives. I think those are different structural relationships, so maybe they should be two alternative foreign keys, with different cascading behaviours.
Again please see the maas-devel thread for politics behind this :(
> Of course my "biggest difference" only gets us to 2 types, out of 4. What are the other differences? It seems to me that:
>
> * "Auto" is like "extra" except it can't be deallocated separately. Could be a separate relationship, or just a boolean attribute.
Whenever you have a boolean attribute, an enum is nearly always what you
want instead, and better. Bools as column types are for mugs IMO, they
restrict what you can do, and I've seen many times where the LP schema
had migrations to move bools to enums as the original design had not
been thought through properly.
> * "Unmanaged" is like "sticky" except the machine on the other end is not a node. But does that matter beyond creation and display? If you set an IP address for a machine's MAC address, then registered that machine as a node, ISTM the IP address would implicitly go from "unmanaged" to "sticky" without affecting the world in any way.
You might have a point here. Let's leave it for now since it doesn't
affect the model itself and is a small implementation detail. We can
always change it later very easily and we'll encapsulate all this detail
inside the manager class anyway.
> There may also be cardinality differences. I can't imagine attaching two MACs to the same "auto" address, but it might make sense for "extra" addresses. Splitting out the relationships may make the rules clearer, and easier to enforce as constraints.
There is no way to attach more than one MAC to an IP with this model.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Julian Edwards (julian-edwards) wrote : | # |
I've now changed this a bit to use a link table between MACAddress and
IPAddress and put MACAddress.
will still be one-to-many rather than many-to-many because I made
IPAddress on the link table unique.
This brings some benefits:
A) no more nullable FK on IPAddress
B) we can put metadata on the link table (which I have done, I've added
nic_alias. See the discussion on maas-devel)
C) we get a more natural MACAddress.
IPAddress.
I'm going to land this because I don't want to be blocked and it's only
slightly different really. We can revisit if necessary of course.
Preview Diff
1 | === modified file 'src/maasserver/enum.py' | |||
2 | --- src/maasserver/enum.py 2014-05-01 20:18:14 +0000 | |||
3 | +++ src/maasserver/enum.py 2014-06-02 05:21:22 +0000 | |||
4 | @@ -14,6 +14,7 @@ | |||
5 | 14 | __metaclass__ = type | 14 | __metaclass__ = type |
6 | 15 | __all__ = [ | 15 | __all__ = [ |
7 | 16 | 'COMPONENT', | 16 | 'COMPONENT', |
8 | 17 | 'IPADDRESS_TYPE', | ||
9 | 17 | 'NODEGROUP_STATUS', | 18 | 'NODEGROUP_STATUS', |
10 | 18 | 'NODEGROUP_STATUS_CHOICES', | 19 | 'NODEGROUP_STATUS_CHOICES', |
11 | 19 | 'NODEGROUPINTERFACE_MANAGEMENT', | 20 | 'NODEGROUPINTERFACE_MANAGEMENT', |
12 | @@ -150,3 +151,18 @@ | |||
13 | 150 | 151 | ||
14 | 151 | NODEGROUPINTERFACE_MANAGEMENT_CHOICES_DICT = ( | 152 | NODEGROUPINTERFACE_MANAGEMENT_CHOICES_DICT = ( |
15 | 152 | OrderedDict(NODEGROUPINTERFACE_MANAGEMENT_CHOICES)) | 153 | OrderedDict(NODEGROUPINTERFACE_MANAGEMENT_CHOICES)) |
16 | 154 | |||
17 | 155 | |||
18 | 156 | class IPADDRESS_TYPE: | ||
19 | 157 | """The vocabulary of possible types of `IPAddress`.""" | ||
20 | 158 | # Automatically assigned. | ||
21 | 159 | AUTO = 0 | ||
22 | 160 | |||
23 | 161 | # Pre-assigned and permanent until removed. | ||
24 | 162 | STICKY = 1 | ||
25 | 163 | |||
26 | 164 | # Not associated to hardware managed by MAAS. | ||
27 | 165 | UNMANAGED = 2 | ||
28 | 166 | |||
29 | 167 | # Additional IP requested by a user for a node. | ||
30 | 168 | EXTRA = 3 | ||
31 | 153 | 169 | ||
32 | === added file 'src/maasserver/migrations/0081_ipaddress_table_and_static_dhcp_ranges.py' | |||
33 | --- src/maasserver/migrations/0081_ipaddress_table_and_static_dhcp_ranges.py 1970-01-01 00:00:00 +0000 | |||
34 | +++ src/maasserver/migrations/0081_ipaddress_table_and_static_dhcp_ranges.py 2014-06-02 05:21:22 +0000 | |||
35 | @@ -0,0 +1,326 @@ | |||
36 | 1 | from django.db import models | ||
37 | 2 | from south.db import db | ||
38 | 3 | # -*- coding: utf-8 -*- | ||
39 | 4 | from south.utils import datetime_utils as datetime | ||
40 | 5 | from south.v2 import SchemaMigration | ||
41 | 6 | |||
42 | 7 | |||
43 | 8 | class Migration(SchemaMigration): | ||
44 | 9 | |||
45 | 10 | def forwards(self, orm): | ||
46 | 11 | # Adding model 'IPAddress' | ||
47 | 12 | db.create_table(u'maasserver_ipaddress', ( | ||
48 | 13 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), | ||
49 | 14 | ('created', self.gf('django.db.models.fields.DateTimeField')()), | ||
50 | 15 | ('updated', self.gf('django.db.models.fields.DateTimeField')()), | ||
51 | 16 | ('ip', self.gf('django.db.models.fields.GenericIPAddressField')(unique=True, max_length=39)), | ||
52 | 17 | ('type', self.gf('django.db.models.fields.IntegerField')(default=0)), | ||
53 | 18 | )) | ||
54 | 19 | db.send_create_signal(u'maasserver', ['IPAddress']) | ||
55 | 20 | |||
56 | 21 | # Adding model 'MACIPAddressLink' | ||
57 | 22 | db.create_table(u'maasserver_macipaddresslink', ( | ||
58 | 23 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), | ||
59 | 24 | ('created', self.gf('django.db.models.fields.DateTimeField')()), | ||
60 | 25 | ('updated', self.gf('django.db.models.fields.DateTimeField')()), | ||
61 | 26 | ('mac_address', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['maasserver.MACAddress'])), | ||
62 | 27 | ('ip_address', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['maasserver.IPAddress'], unique=True)), | ||
63 | 28 | ('nic_alias', self.gf('django.db.models.fields.IntegerField')(default=None, null=True, blank=True)), | ||
64 | 29 | )) | ||
65 | 30 | db.send_create_signal(u'maasserver', ['MACIPAddressLink']) | ||
66 | 31 | |||
67 | 32 | # Adding unique constraint on 'MACIPAddressLink', fields ['ip_address', 'mac_address'] | ||
68 | 33 | db.create_unique(u'maasserver_macipaddresslink', ['ip_address_id', 'mac_address_id']) | ||
69 | 34 | |||
70 | 35 | # Adding field 'NodeGroupInterface.static_ip_range_low' | ||
71 | 36 | db.add_column(u'maasserver_nodegroupinterface', 'static_ip_range_low', | ||
72 | 37 | self.gf('django.db.models.fields.GenericIPAddressField')(default=None, max_length=39, null=True, blank=True), | ||
73 | 38 | keep_default=False) | ||
74 | 39 | |||
75 | 40 | # Adding field 'NodeGroupInterface.static_ip_range_high' | ||
76 | 41 | db.add_column(u'maasserver_nodegroupinterface', 'static_ip_range_high', | ||
77 | 42 | self.gf('django.db.models.fields.GenericIPAddressField')(default=None, max_length=39, null=True, blank=True), | ||
78 | 43 | keep_default=False) | ||
79 | 44 | |||
80 | 45 | |||
81 | 46 | def backwards(self, orm): | ||
82 | 47 | # Removing unique constraint on 'MACIPAddressLink', fields ['ip_address', 'mac_address'] | ||
83 | 48 | db.delete_unique(u'maasserver_macipaddresslink', ['ip_address_id', 'mac_address_id']) | ||
84 | 49 | |||
85 | 50 | # Deleting model 'IPAddress' | ||
86 | 51 | db.delete_table(u'maasserver_ipaddress') | ||
87 | 52 | |||
88 | 53 | # Deleting model 'MACIPAddressLink' | ||
89 | 54 | db.delete_table(u'maasserver_macipaddresslink') | ||
90 | 55 | |||
91 | 56 | # Deleting field 'NodeGroupInterface.static_ip_range_low' | ||
92 | 57 | db.delete_column(u'maasserver_nodegroupinterface', 'static_ip_range_low') | ||
93 | 58 | |||
94 | 59 | # Deleting field 'NodeGroupInterface.static_ip_range_high' | ||
95 | 60 | db.delete_column(u'maasserver_nodegroupinterface', 'static_ip_range_high') | ||
96 | 61 | |||
97 | 62 | |||
98 | 63 | models = { | ||
99 | 64 | u'auth.group': { | ||
100 | 65 | 'Meta': {'object_name': 'Group'}, | ||
101 | 66 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
102 | 67 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
103 | 68 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
104 | 69 | }, | ||
105 | 70 | u'auth.permission': { | ||
106 | 71 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
107 | 72 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
108 | 73 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
109 | 74 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
110 | 75 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
111 | 76 | }, | ||
112 | 77 | u'auth.user': { | ||
113 | 78 | 'Meta': {'object_name': 'User'}, | ||
114 | 79 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
115 | 80 | 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
116 | 81 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
117 | 82 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
118 | 83 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
119 | 84 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
120 | 85 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
121 | 86 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
122 | 87 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
123 | 88 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
124 | 89 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
125 | 90 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
126 | 91 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | ||
127 | 92 | }, | ||
128 | 93 | u'contenttypes.contenttype': { | ||
129 | 94 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
130 | 95 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
131 | 96 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
132 | 97 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
133 | 98 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
134 | 99 | }, | ||
135 | 100 | u'maasserver.bootimage': { | ||
136 | 101 | 'Meta': {'unique_together': "((u'nodegroup', u'osystem', u'architecture', u'subarchitecture', u'release', u'purpose', u'label'),)", 'object_name': 'BootImage'}, | ||
137 | 102 | 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
138 | 103 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
139 | 104 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
140 | 105 | 'label': ('django.db.models.fields.CharField', [], {'default': "u'release'", 'max_length': '255'}), | ||
141 | 106 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
142 | 107 | 'osystem': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
143 | 108 | 'purpose': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
144 | 109 | 'release': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
145 | 110 | 'subarchitecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
146 | 111 | 'supported_subarches': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), | ||
147 | 112 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
148 | 113 | }, | ||
149 | 114 | u'maasserver.bootsource': { | ||
150 | 115 | 'Meta': {'object_name': 'BootSource'}, | ||
151 | 116 | 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}), | ||
152 | 117 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
153 | 118 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
154 | 119 | 'keyring_data': ('maasserver.fields.EditableBinaryField', [], {'blank': 'True'}), | ||
155 | 120 | 'keyring_filename': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}), | ||
156 | 121 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
157 | 122 | 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) | ||
158 | 123 | }, | ||
159 | 124 | u'maasserver.bootsourceselection': { | ||
160 | 125 | 'Meta': {'object_name': 'BootSourceSelection'}, | ||
161 | 126 | 'arches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
162 | 127 | 'boot_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.BootSource']"}), | ||
163 | 128 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
164 | 129 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
165 | 130 | 'labels': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
166 | 131 | 'release': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
167 | 132 | 'subarches': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'text'", 'null': 'True', 'blank': 'True'}), | ||
168 | 133 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
169 | 134 | }, | ||
170 | 135 | u'maasserver.componenterror': { | ||
171 | 136 | 'Meta': {'object_name': 'ComponentError'}, | ||
172 | 137 | 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}), | ||
173 | 138 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
174 | 139 | 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}), | ||
175 | 140 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
176 | 141 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
177 | 142 | }, | ||
178 | 143 | u'maasserver.config': { | ||
179 | 144 | 'Meta': {'object_name': 'Config'}, | ||
180 | 145 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
181 | 146 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
182 | 147 | 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'}) | ||
183 | 148 | }, | ||
184 | 149 | u'maasserver.dhcplease': { | ||
185 | 150 | 'Meta': {'object_name': 'DHCPLease'}, | ||
186 | 151 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
187 | 152 | 'ip': ('django.db.models.fields.IPAddressField', [], {'unique': 'True', 'max_length': '15'}), | ||
188 | 153 | 'mac': ('maasserver.fields.MACAddressField', [], {}), | ||
189 | 154 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}) | ||
190 | 155 | }, | ||
191 | 156 | u'maasserver.downloadprogress': { | ||
192 | 157 | 'Meta': {'object_name': 'DownloadProgress'}, | ||
193 | 158 | 'bytes_downloaded': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), | ||
194 | 159 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
195 | 160 | 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}), | ||
196 | 161 | 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
197 | 162 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
198 | 163 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
199 | 164 | 'size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), | ||
200 | 165 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
201 | 166 | }, | ||
202 | 167 | u'maasserver.filestorage': { | ||
203 | 168 | 'Meta': {'unique_together': "((u'filename', u'owner'),)", 'object_name': 'FileStorage'}, | ||
204 | 169 | 'content': ('metadataserver.fields.BinaryField', [], {'blank': 'True'}), | ||
205 | 170 | 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
206 | 171 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
207 | 172 | 'key': ('django.db.models.fields.CharField', [], {'default': "u'23d4ee34-ea01-11e3-8dfe-002215205ce8'", 'unique': 'True', 'max_length': '36'}), | ||
208 | 173 | 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) | ||
209 | 174 | }, | ||
210 | 175 | u'maasserver.ipaddress': { | ||
211 | 176 | 'Meta': {'object_name': 'IPAddress'}, | ||
212 | 177 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
213 | 178 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
214 | 179 | 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
215 | 180 | 'type': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
216 | 181 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
217 | 182 | }, | ||
218 | 183 | u'maasserver.macaddress': { | ||
219 | 184 | 'Meta': {'object_name': 'MACAddress'}, | ||
220 | 185 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
221 | 186 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
222 | 187 | 'ip_addresses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.IPAddress']", 'through': u"orm['maasserver.MACIPAddressLink']", 'symmetrical': 'False'}), | ||
223 | 188 | 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}), | ||
224 | 189 | 'networks': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Network']", 'symmetrical': 'False', 'blank': 'True'}), | ||
225 | 190 | 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}), | ||
226 | 191 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
227 | 192 | }, | ||
228 | 193 | u'maasserver.macipaddresslink': { | ||
229 | 194 | 'Meta': {'unique_together': "((u'ip_address', u'mac_address'),)", 'object_name': 'MACIPAddressLink'}, | ||
230 | 195 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
231 | 196 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
232 | 197 | 'ip_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.IPAddress']", 'unique': 'True'}), | ||
233 | 198 | 'mac_address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.MACAddress']"}), | ||
234 | 199 | 'nic_alias': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), | ||
235 | 200 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
236 | 201 | }, | ||
237 | 202 | u'maasserver.network': { | ||
238 | 203 | 'Meta': {'object_name': 'Network'}, | ||
239 | 204 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
240 | 205 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
241 | 206 | 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'unique': 'True', 'max_length': '39'}), | ||
242 | 207 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), | ||
243 | 208 | 'netmask': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), | ||
244 | 209 | 'vlan_tag': ('django.db.models.fields.PositiveSmallIntegerField', [], {'unique': 'True', 'null': 'True', 'blank': 'True'}) | ||
245 | 210 | }, | ||
246 | 211 | u'maasserver.node': { | ||
247 | 212 | 'Meta': {'object_name': 'Node'}, | ||
248 | 213 | 'agent_name': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
249 | 214 | 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '31'}), | ||
250 | 215 | 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
251 | 216 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
252 | 217 | 'distro_series': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
253 | 218 | 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
254 | 219 | 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'unique': 'True', 'max_length': '255', 'blank': 'True'}), | ||
255 | 220 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
256 | 221 | 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
257 | 222 | 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
258 | 223 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}), | ||
259 | 224 | 'osystem': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '20', 'blank': 'True'}), | ||
260 | 225 | 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), | ||
261 | 226 | 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}), | ||
262 | 227 | 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}), | ||
263 | 228 | 'routers': ('djorm_pgarray.fields.ArrayField', [], {'default': 'None', 'dbtype': "u'macaddr'", 'null': 'True', 'blank': 'True'}), | ||
264 | 229 | 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}), | ||
265 | 230 | 'storage': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
266 | 231 | 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-23d247e2-ea01-11e3-8dfe-002215205ce8'", 'unique': 'True', 'max_length': '41'}), | ||
267 | 232 | 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}), | ||
268 | 233 | 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'null': 'True'}), | ||
269 | 234 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
270 | 235 | 'zone': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Zone']", 'on_delete': 'models.SET_DEFAULT'}) | ||
271 | 236 | }, | ||
272 | 237 | u'maasserver.nodegroup': { | ||
273 | 238 | 'Meta': {'object_name': 'NodeGroup'}, | ||
274 | 239 | 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}), | ||
275 | 240 | 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Token']", 'unique': 'True'}), | ||
276 | 241 | 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}), | ||
277 | 242 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
278 | 243 | 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
279 | 244 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
280 | 245 | 'maas_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
281 | 246 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}), | ||
282 | 247 | 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
283 | 248 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
284 | 249 | 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}) | ||
285 | 250 | }, | ||
286 | 251 | u'maasserver.nodegroupinterface': { | ||
287 | 252 | 'Meta': {'unique_together': "((u'nodegroup', u'interface'),)", 'object_name': 'NodeGroupInterface'}, | ||
288 | 253 | 'broadcast_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
289 | 254 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
290 | 255 | 'foreign_dhcp_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
291 | 256 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
292 | 257 | 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}), | ||
293 | 258 | 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), | ||
294 | 259 | 'ip_range_high': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
295 | 260 | 'ip_range_low': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
296 | 261 | 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | ||
297 | 262 | 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}), | ||
298 | 263 | 'router_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
299 | 264 | 'static_ip_range_high': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
300 | 265 | 'static_ip_range_low': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
301 | 266 | 'subnet_mask': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}), | ||
302 | 267 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
303 | 268 | }, | ||
304 | 269 | u'maasserver.sshkey': { | ||
305 | 270 | 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'}, | ||
306 | 271 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
307 | 272 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
308 | 273 | 'key': ('django.db.models.fields.TextField', [], {}), | ||
309 | 274 | 'updated': ('django.db.models.fields.DateTimeField', [], {}), | ||
310 | 275 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) | ||
311 | 276 | }, | ||
312 | 277 | u'maasserver.tag': { | ||
313 | 278 | 'Meta': {'object_name': 'Tag'}, | ||
314 | 279 | 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
315 | 280 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
316 | 281 | 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
317 | 282 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
318 | 283 | 'kernel_opts': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), | ||
319 | 284 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}), | ||
320 | 285 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
321 | 286 | }, | ||
322 | 287 | u'maasserver.userprofile': { | ||
323 | 288 | 'Meta': {'object_name': 'UserProfile'}, | ||
324 | 289 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
325 | 290 | 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) | ||
326 | 291 | }, | ||
327 | 292 | u'maasserver.zone': { | ||
328 | 293 | 'Meta': {'ordering': "[u'name']", 'object_name': 'Zone'}, | ||
329 | 294 | 'created': ('django.db.models.fields.DateTimeField', [], {}), | ||
330 | 295 | 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
331 | 296 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
332 | 297 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}), | ||
333 | 298 | 'updated': ('django.db.models.fields.DateTimeField', [], {}) | ||
334 | 299 | }, | ||
335 | 300 | u'piston.consumer': { | ||
336 | 301 | 'Meta': {'object_name': 'Consumer'}, | ||
337 | 302 | 'description': ('django.db.models.fields.TextField', [], {}), | ||
338 | 303 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
339 | 304 | 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}), | ||
340 | 305 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
341 | 306 | 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}), | ||
342 | 307 | 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}), | ||
343 | 308 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': u"orm['auth.User']"}) | ||
344 | 309 | }, | ||
345 | 310 | u'piston.token': { | ||
346 | 311 | 'Meta': {'object_name': 'Token'}, | ||
347 | 312 | 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), | ||
348 | 313 | 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
349 | 314 | 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['piston.Consumer']"}), | ||
350 | 315 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
351 | 316 | 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
352 | 317 | 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}), | ||
353 | 318 | 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}), | ||
354 | 319 | 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1401677636L'}), | ||
355 | 320 | 'token_type': ('django.db.models.fields.IntegerField', [], {}), | ||
356 | 321 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': u"orm['auth.User']"}), | ||
357 | 322 | 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'}) | ||
358 | 323 | } | ||
359 | 324 | } | ||
360 | 325 | |||
361 | 326 | complete_apps = ['maasserver'] | ||
362 | 0 | \ No newline at end of file | 327 | \ No newline at end of file |
363 | 1 | 328 | ||
364 | === modified file 'src/maasserver/models/__init__.py' | |||
365 | --- src/maasserver/models/__init__.py 2014-05-16 09:00:55 +0000 | |||
366 | +++ src/maasserver/models/__init__.py 2014-06-02 05:21:22 +0000 | |||
367 | @@ -51,7 +51,9 @@ | |||
368 | 51 | from maasserver.models.dhcplease import DHCPLease | 51 | from maasserver.models.dhcplease import DHCPLease |
369 | 52 | from maasserver.models.downloadprogress import DownloadProgress | 52 | from maasserver.models.downloadprogress import DownloadProgress |
370 | 53 | from maasserver.models.filestorage import FileStorage | 53 | from maasserver.models.filestorage import FileStorage |
371 | 54 | from maasserver.models.ipaddress import IPAddress | ||
372 | 54 | from maasserver.models.macaddress import MACAddress | 55 | from maasserver.models.macaddress import MACAddress |
373 | 56 | from maasserver.models.macipaddresslink import MACIPAddressLink | ||
374 | 55 | from maasserver.models.network import Network | 57 | from maasserver.models.network import Network |
375 | 56 | from maasserver.models.node import Node | 58 | from maasserver.models.node import Node |
376 | 57 | from maasserver.models.nodegroup import NodeGroup | 59 | from maasserver.models.nodegroup import NodeGroup |
377 | @@ -68,8 +70,9 @@ | |||
378 | 68 | # export in __all__. | 70 | # export in __all__. |
379 | 69 | ignore_unused( | 71 | ignore_unused( |
380 | 70 | BootImage, ComponentError, Config, DHCPLease, DownloadProgress, | 72 | BootImage, ComponentError, Config, DHCPLease, DownloadProgress, |
383 | 71 | FileStorage, MACAddress, Network, NodeGroup, SSHKey, Tag, UserProfile, | 73 | FileStorage, IPAddress, MACAddress, MACIPAddressLink, Network, |
384 | 72 | NodeGroupInterface, Zone, logger) | 74 | NodeGroup, SSHKey, Tag, UserProfile, NodeGroupInterface, Zone, |
385 | 75 | logger) | ||
386 | 73 | 76 | ||
387 | 74 | 77 | ||
388 | 75 | # Connect the 'create_user' method to the post save signal of User. | 78 | # Connect the 'create_user' method to the post save signal of User. |
389 | 76 | 79 | ||
390 | === added file 'src/maasserver/models/ipaddress.py' | |||
391 | --- src/maasserver/models/ipaddress.py 1970-01-01 00:00:00 +0000 | |||
392 | +++ src/maasserver/models/ipaddress.py 2014-06-02 05:21:22 +0000 | |||
393 | @@ -0,0 +1,53 @@ | |||
394 | 1 | # Copyright 2014 Canonical Ltd. This software is licensed under the | ||
395 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
396 | 3 | |||
397 | 4 | """Model definition for IPAddress. | ||
398 | 5 | |||
399 | 6 | Contains all the in-use static IP addresses that are allocated by MAAS. | ||
400 | 7 | Generally speaking, these are written out to the DHCP server as "host" | ||
401 | 8 | blocks which will tie MACs into a specific IP. The IPs are separate | ||
402 | 9 | from the dynamic range that the DHCP server itself allocates to unknown | ||
403 | 10 | clients. | ||
404 | 11 | """ | ||
405 | 12 | |||
406 | 13 | from __future__ import ( | ||
407 | 14 | absolute_import, | ||
408 | 15 | print_function, | ||
409 | 16 | unicode_literals, | ||
410 | 17 | ) | ||
411 | 18 | |||
412 | 19 | str = None | ||
413 | 20 | |||
414 | 21 | __metaclass__ = type | ||
415 | 22 | __all__ = [ | ||
416 | 23 | 'IPAddress', | ||
417 | 24 | ] | ||
418 | 25 | |||
419 | 26 | |||
420 | 27 | from django.db.models import ( | ||
421 | 28 | GenericIPAddressField, | ||
422 | 29 | IntegerField, | ||
423 | 30 | ) | ||
424 | 31 | from maasserver import DefaultMeta | ||
425 | 32 | from maasserver.enum import IPADDRESS_TYPE | ||
426 | 33 | from maasserver.models.cleansave import CleanSave | ||
427 | 34 | from maasserver.models.timestampedmodel import TimestampedModel | ||
428 | 35 | |||
429 | 36 | |||
430 | 37 | class IPAddress(CleanSave, TimestampedModel): | ||
431 | 38 | |||
432 | 39 | class Meta(DefaultMeta): | ||
433 | 40 | verbose_name = "IP Address" | ||
434 | 41 | verbose_name_plural = "IP Addresses" | ||
435 | 42 | |||
436 | 43 | ip = GenericIPAddressField( | ||
437 | 44 | unique=True, null=False, editable=False, blank=False) | ||
438 | 45 | |||
439 | 46 | # The MACIPAddressLink table is used to link IPAddress to | ||
440 | 47 | # MACAddress. See MACAddress.ip_addresses. | ||
441 | 48 | |||
442 | 49 | type = IntegerField( | ||
443 | 50 | editable=False, null=False, blank=False, default=IPADDRESS_TYPE.AUTO) | ||
444 | 51 | |||
445 | 52 | def __unicode__(self): | ||
446 | 53 | return "<IPAddress %s>" % self.ip | ||
447 | 0 | 54 | ||
448 | === modified file 'src/maasserver/models/macaddress.py' | |||
449 | --- src/maasserver/models/macaddress.py 2014-02-27 23:37:18 +0000 | |||
450 | +++ src/maasserver/models/macaddress.py 2014-06-02 05:21:22 +0000 | |||
451 | @@ -50,6 +50,12 @@ | |||
452 | 50 | 50 | ||
453 | 51 | networks = ManyToManyField('maasserver.Network', blank=True) | 51 | networks = ManyToManyField('maasserver.Network', blank=True) |
454 | 52 | 52 | ||
455 | 53 | ip_addresses = ManyToManyField( | ||
456 | 54 | 'maasserver.IPAddress', through='maasserver.MACIPAddressLink', | ||
457 | 55 | blank=True) | ||
458 | 56 | |||
459 | 57 | # future columns: tags, nic_name, metadata, bonding info | ||
460 | 58 | |||
461 | 53 | objects = BulkManager() | 59 | objects = BulkManager() |
462 | 54 | 60 | ||
463 | 55 | class Meta(DefaultMeta): | 61 | class Meta(DefaultMeta): |
464 | 56 | 62 | ||
465 | === added file 'src/maasserver/models/macipaddresslink.py' | |||
466 | --- src/maasserver/models/macipaddresslink.py 1970-01-01 00:00:00 +0000 | |||
467 | +++ src/maasserver/models/macipaddresslink.py 2014-06-02 05:21:22 +0000 | |||
468 | @@ -0,0 +1,44 @@ | |||
469 | 1 | # Copyright 2014 Canonical Ltd. This software is licensed under the | ||
470 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
471 | 3 | |||
472 | 4 | """Model definition for MACIPAddressLink. | ||
473 | 5 | |||
474 | 6 | Maintains a relationship between MACAddress and IPAddress. This is defined | ||
475 | 7 | instead of using Django's auto-generated link table because it also contains | ||
476 | 8 | additional metadata about the link, such as a NIC alias. | ||
477 | 9 | """ | ||
478 | 10 | |||
479 | 11 | from __future__ import ( | ||
480 | 12 | absolute_import, | ||
481 | 13 | print_function, | ||
482 | 14 | unicode_literals, | ||
483 | 15 | ) | ||
484 | 16 | |||
485 | 17 | str = None | ||
486 | 18 | |||
487 | 19 | __metaclass__ = type | ||
488 | 20 | __all__ = [ | ||
489 | 21 | 'MACIPAddressLink', | ||
490 | 22 | ] | ||
491 | 23 | |||
492 | 24 | |||
493 | 25 | from django.db.models import ( | ||
494 | 26 | ForeignKey, | ||
495 | 27 | IntegerField, | ||
496 | 28 | ) | ||
497 | 29 | from maasserver import DefaultMeta | ||
498 | 30 | from maasserver.models.cleansave import CleanSave | ||
499 | 31 | from maasserver.models.timestampedmodel import TimestampedModel | ||
500 | 32 | |||
501 | 33 | |||
502 | 34 | class MACIPAddressLink(CleanSave, TimestampedModel): | ||
503 | 35 | |||
504 | 36 | class Meta(DefaultMeta): | ||
505 | 37 | unique_together = ('ip_address', 'mac_address') | ||
506 | 38 | |||
507 | 39 | mac_address = ForeignKey('maasserver.MACAddress') | ||
508 | 40 | ip_address = ForeignKey('maasserver.IPAddress', unique=True) | ||
509 | 41 | |||
510 | 42 | # Optional NIC alias for multi-homed NICs (e.g. 'eth0:1') | ||
511 | 43 | nic_alias = IntegerField( | ||
512 | 44 | editable=True, null=True, blank=True, default=None) | ||
513 | 0 | 45 | ||
514 | === modified file 'src/maasserver/models/nodegroupinterface.py' | |||
515 | --- src/maasserver/models/nodegroupinterface.py 2014-03-31 08:19:12 +0000 | |||
516 | +++ src/maasserver/models/nodegroupinterface.py 2014-06-02 05:21:22 +0000 | |||
517 | @@ -78,6 +78,10 @@ | |||
518 | 78 | editable=True, unique=False, blank=True, null=True, default=None) | 78 | editable=True, unique=False, blank=True, null=True, default=None) |
519 | 79 | ip_range_high = GenericIPAddressField( | 79 | ip_range_high = GenericIPAddressField( |
520 | 80 | editable=True, unique=False, blank=True, null=True, default=None) | 80 | editable=True, unique=False, blank=True, null=True, default=None) |
521 | 81 | static_ip_range_low = GenericIPAddressField( | ||
522 | 82 | editable=True, unique=False, blank=True, null=True, default=None) | ||
523 | 83 | static_ip_range_high = GenericIPAddressField( | ||
524 | 84 | editable=True, unique=False, blank=True, null=True, default=None) | ||
525 | 81 | 85 | ||
526 | 82 | # Foreign DHCP server address, if any, that was detected on this | 86 | # Foreign DHCP server address, if any, that was detected on this |
527 | 83 | # interface. | 87 | # interface. |
I want to make more changes to this so I've marked it WIP.