Raphaël Badin has proposed merging lp:~rvb/maas/add-nodegroup_interface into
lp:maas.
Requested reviews:
MAAS Maintainers (maas-maintainers)
For more details, see:
https://code.launchpad.net/~rvb/maas/add-nodegroup_interface/+merge/123914
This is branch is the first branch in a series of branches aimed at adding
support for multiple interfaces attached to a particular nodegroup (i.e.
cluster controller). The plan is to add support in the db for multiple
interfaces but to restrict the number of managed (i.e. an interface on which
MAAS exposes a DHCP service) interface to only one for now. This should allow
for a transition as smooth as possible from the model that we have right now.
This branch adds the new model: nodegroup_interface. With some renaming (for
clarity), it boils down to duplicating the network-related fields present on
nodegroup (to be removed in a followup branch) and move them into the new model.
= Pre-imp =
This was pre-imp with Julian.
= Notes =
Some fields have been renamed (compared to the fields in nodegroup):
- 'worker_ip' is now named 'ip'. This is the IP for the interface.
- 'dhcp_interfaces' is now named 'interface'. Singular because there is a
one-to-many relationship between nodegroup and nodegroupinterface. And I
dropped the 'dhcp_' prefix because this new model is now simply describing
networks and interfaces. The fact that this is used for DHCP does not need to
be engraved in the model itself.
--
https://code.launchpad.net/~rvb/maas/add-nodegroup_interface/+merge/123914
Your team MAAS Maintainers is requested to review the proposed merge of
lp:~rvb/maas/add-nodegroup_interface into lp:maas.
=== modified file 'src/maasserver/enum.py'
--- src/maasserver/enum.py 2012-09-10 16:45:38 +0000
+++ src/maasserver/enum.py 2012-09-12 09:53:23 +0000
@@ -160,3 +160,22 @@
(NODEGROUP_STATUS.ACCEPTED, "Accepted"),
(NODEGROUP_STATUS.REJECTED, "Rejected"),
)
+
+
+class NODEGROUPINTERFACE_STATUS:
+ """The vocabulary of a `NodeGroupInterface`'s possible statuses."""
+ # A nodegroupinterface starts out as UNMANAGED.
+ DEFAULT_STATUS = 0
+
+ #: MAAS manages IP address assignments on this interface.
+ UNMANAGED = 0
+ #: MAAS does not manage IP address assignments on this interface.
+ MANAGED = 1
+
+
+# Django choices for NODEGROUP_STATUS: sequence of tuples (key, UI
+# representation).
+NODEGROUPINTERFACE_STATUS_CHOICES = (
+ (NODEGROUPINTERFACE_STATUS.UNMANAGED, "Unmanaged"),
+ (NODEGROUPINTERFACE_STATUS.MANAGED, "Managed"),
+ )
=== added file 'src/maasserver/migrations/0023_add_nodegroupinterface.py'
--- src/maasserver/migrations/0023_add_nodegroupinterface.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/migrations/0023_add_nodegroupinterface.py 2012-09-12 09:53:23 +0000
@@ -0,0 +1,198 @@
+# encoding: utf-8
+import datetime
+
+from django.db import models
+from south.db import db
+from south.v2 import SchemaMigration
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'NodeGroupInterface'
+ db.create_table(u'maasserver_nodegroupinterface', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('created', self.gf('django.db.models.fields.DateTimeField')()),
+ ('updated', self.gf('django.db.models.fields.DateTimeField')()),
+ ('ip', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),
+ ('nodegroup', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['maasserver.NodeGroup'])),
+ ('status', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('interface', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, blank=True)),
+ ('subnet_mask', self.gf('django.db.models.fields.IPAddressField')(default=None, max_length=15, null=True, blank=True)),
+ ('broadcast_ip', self.gf('django.db.models.fields.IPAddressField')(default=None, max_length=15, null=True, blank=True)),
+ ('router_ip', self.gf('django.db.models.fields.IPAddressField')(default=None, max_length=15, null=True, blank=True)),
+ ('ip_range_low', self.gf('django.db.models.fields.IPAddressField')(default=None, max_length=15, unique=True, null=True, blank=True)),
+ ('ip_range_high', self.gf('django.db.models.fields.IPAddressField')(default=None, max_length=15, unique=True, null=True, blank=True)),
+ ))
+ db.send_create_signal(u'maasserver', ['NodeGroupInterface'])
+
+ # Adding unique constraint on 'NodeGroupInterface', fields ['nodegroup', 'interface']
+ db.create_unique(u'maasserver_nodegroupinterface', ['nodegroup_id', 'interface'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'NodeGroupInterface', fields ['nodegroup', 'interface']
+ db.delete_unique(u'maasserver_nodegroupinterface', ['nodegroup_id', 'interface'])
+
+ # Deleting model 'NodeGroupInterface'
+ db.delete_table(u'maasserver_nodegroupinterface')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'maasserver.config': {
+ 'Meta': {'object_name': 'Config'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'})
+ },
+ u'maasserver.dhcplease': {
+ 'Meta': {'object_name': 'DHCPLease'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.IPAddressField', [], {'unique': 'True', 'max_length': '15'}),
+ 'mac': ('maasserver.fields.MACAddressField', [], {}),
+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"})
+ },
+ u'maasserver.filestorage': {
+ 'Meta': {'object_name': 'FileStorage'},
+ 'data': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ u'maasserver.macaddress': {
+ 'Meta': {'object_name': 'MACAddress'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
+ },
+ u'maasserver.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'after_commissioning_action': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'architecture': ('django.db.models.fields.CharField', [], {'default': "u'i386'", 'max_length': '10'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
+ 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
+ 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}),
+ 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-29a5206a-fc12-11e1-bbff-3c970e0e56dc'", 'unique': 'True', 'max_length': '41'}),
+ 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Token']", 'null': 'True'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
+ },
+ u'maasserver.nodegroup': {
+ 'Meta': {'object_name': 'NodeGroup'},
+ 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}),
+ 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Token']", 'unique': 'True'}),
+ 'broadcast_ip': ('django.db.models.fields.IPAddressField', [], {'default': "u''", 'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'dhcp_interfaces': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
+ 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_range_high': ('django.db.models.fields.IPAddressField', [], {'default': "u''", 'max_length': '15', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'ip_range_low': ('django.db.models.fields.IPAddressField', [], {'default': "u''", 'max_length': '15', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'router_ip': ('django.db.models.fields.IPAddressField', [], {'default': "u''", 'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'subnet_mask': ('django.db.models.fields.IPAddressField', [], {'default': "u''", 'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
+ 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}),
+ 'worker_ip': ('django.db.models.fields.IPAddressField', [], {'unique': 'True', 'max_length': '15'})
+ },
+ u'maasserver.nodegroupinterface': {
+ 'Meta': {'unique_together': "((u'nodegroup', u'interface'),)", 'object_name': 'NodeGroupInterface'},
+ 'broadcast_ip': ('django.db.models.fields.IPAddressField', [], {'default': 'None', 'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
+ 'ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'ip_range_high': ('django.db.models.fields.IPAddressField', [], {'default': 'None', 'max_length': '15', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'ip_range_low': ('django.db.models.fields.IPAddressField', [], {'default': 'None', 'max_length': '15', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
+ 'router_ip': ('django.db.models.fields.IPAddressField', [], {'default': 'None', 'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'subnet_mask': ('django.db.models.fields.IPAddressField', [], {'default': 'None', 'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
+ },
+ u'maasserver.sshkey': {
+ 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.TextField', [], {}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ u'maasserver.userprofile': {
+ 'Meta': {'object_name': 'UserProfile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
+ },
+ 'piston.consumer': {
+ 'Meta': {'object_name': 'Consumer'},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': "orm['auth.User']"})
+ },
+ 'piston.token': {
+ 'Meta': {'object_name': 'Token'},
+ 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Consumer']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1347369065L'}),
+ 'token_type': ('django.db.models.fields.IntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'})
+ }
+ }
+
+ complete_apps = ['maasserver']
=== modified file 'src/maasserver/models/__init__.py'
--- src/maasserver/models/__init__.py 2012-08-16 13:38:51 +0000
+++ src/maasserver/models/__init__.py 2012-09-12 09:53:23 +0000
@@ -18,6 +18,7 @@
'MACAddress',
'Node',
'NodeGroup',
+ 'NodeGroupInterface',
'SSHKey',
'UserProfile',
]
@@ -35,6 +36,7 @@
from maasserver.models.macaddress import MACAddress
from maasserver.models.node import Node
from maasserver.models.nodegroup import NodeGroup
+from maasserver.models.nodegroupinterface import NodeGroupInterface
from maasserver.models.sshkey import SSHKey
from maasserver.models.user import create_user
from maasserver.models.userprofile import UserProfile
@@ -49,7 +51,7 @@
# export in __all__.
ignore_unused(
Config, DHCPLease, FileStorage, MACAddress, NodeGroup, SSHKey,
- UserProfile)
+ UserProfile, NodeGroupInterface)
# Connect the 'create_user' method to the post save signal of User.
=== added file 'src/maasserver/models/nodegroupinterface.py'
--- src/maasserver/models/nodegroupinterface.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/models/nodegroupinterface.py 2012-09-12 09:53:23 +0000
@@ -0,0 +1,63 @@
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Model definition for NodeGroupInterface."""
+
+from __future__ import (
+ absolute_import,
+ print_function,
+ unicode_literals,
+ )
+
+__metaclass__ = type
+__all__ = [
+ 'NodeGroupInterface',
+ ]
+
+
+from django.db.models import (
+ CharField,
+ ForeignKey,
+ IntegerField,
+ IPAddressField,
+ )
+from maasserver import DefaultMeta
+from maasserver.enum import (
+ NODEGROUPINTERFACE_STATUS,
+ NODEGROUPINTERFACE_STATUS_CHOICES,
+ )
+from maasserver.models.timestampedmodel import TimestampedModel
+
+
+class NodeGroupInterface(TimestampedModel):
+
+ class Meta(DefaultMeta):
+ unique_together = ('nodegroup', 'interface')
+
+ # Static IP of the interface.
+ ip = IPAddressField(null=False, editable=True)
+
+ # The `NodeGroup` this interface belongs to.
+ nodegroup = ForeignKey(
+ 'maasserver.NodeGroup', editable=True, null=False, blank=False)
+
+ status = IntegerField(
+ choices=NODEGROUPINTERFACE_STATUS_CHOICES, editable=False,
+ default=NODEGROUPINTERFACE_STATUS.DEFAULT_STATUS)
+
+ # DHCP server settings.
+ interface = CharField(
+ blank=True, editable=False, max_length=255, default='')
+ subnet_mask = IPAddressField(
+ editable=True, unique=False, blank=True, null=True, default=None)
+ broadcast_ip = IPAddressField(
+ editable=True, unique=False, blank=True, null=True, default=None)
+ router_ip = IPAddressField(
+ editable=True, unique=False, blank=True, null=True, default=None)
+ ip_range_low = IPAddressField(
+ editable=True, unique=True, blank=True, null=True, default=None)
+ ip_range_high = IPAddressField(
+ editable=True, unique=True, blank=True, null=True, default=None)
+
+ def __repr__(self):
+ return "<NodeGroupInterface %r,%s>" % (self.nodegroup, self.interface)
_______________________________________________
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : [email protected]
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help : https://help.launchpad.net/ListHelp