Merge lp:~rvb/maas/ui-update-fqdn-1.2 into lp:maas/1.2

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 1303
Proposed branch: lp:~rvb/maas/ui-update-fqdn-1.2
Merge into: lp:maas/1.2
Diff against target: 881 lines (+505/-58)
18 files modified
src/maasserver/forms.py (+9/-0)
src/maasserver/migrations/0043_unique_hostname_preparation.py (+218/-0)
src/maasserver/migrations/0044_node_hostname_unique.py (+201/-0)
src/maasserver/models/node.py (+2/-1)
src/maasserver/templates/maasserver/node_edit.html (+2/-0)
src/maasserver/templates/maasserver/node_view.html (+4/-4)
src/maasserver/templates/maasserver/nodes_listing.html (+9/-6)
src/maasserver/testing/factory.py (+3/-3)
src/maasserver/tests/test_api.py (+15/-7)
src/maasserver/tests/test_dhcplease.py (+3/-3)
src/maasserver/tests/test_dns.py (+1/-1)
src/maasserver/tests/test_forms.py (+0/-12)
src/maasserver/tests/test_node.py (+2/-3)
src/maasserver/tests/test_node_constraint_filter.py (+2/-2)
src/maasserver/tests/test_views_nodes.py (+18/-1)
src/maasserver/tests/test_views_tags.py (+10/-14)
src/maasserver/views/nodes.py (+2/-0)
src/maasserver/views/tags.py (+4/-1)
To merge this branch: bzr merge lp:~rvb/maas/ui-update-fqdn-1.2
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Review via email: mp+134663@code.launchpad.net

Commit message

Backport of 1335 (and required db migration merged in revision 1330).

Description of the change

Backport of 1335 (and required db migration merged in revision 1330).

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

This is a backport of 1335 (and the required db migration merged in revision 1330). Self-approving.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/forms.py'
--- src/maasserver/forms.py 2012-11-16 07:43:42 +0000
+++ src/maasserver/forms.py 2012-11-16 13:58:29 +0000
@@ -152,6 +152,15 @@
152 initial=ARCHITECTURE.i386,152 initial=ARCHITECTURE.i386,
153 error_messages={'invalid_choice': INVALID_ARCHITECTURE_MESSAGE})153 error_messages={'invalid_choice': INVALID_ARCHITECTURE_MESSAGE})
154154
155 hostname = forms.CharField(
156 label="Host name", required=False, help_text=(
157 "The FQDN (Fully Qualified Domain Name) is derived from the "
158 "host name: If the cluster controller for this node is managing "
159 "DNS then the domain part in the host name (if any) is replaced "
160 "by the domain defined on the cluster; if the cluster controller "
161 "does not manage DNS, then the host name as entered will be the "
162 "FQDN."))
163
155 class Meta:164 class Meta:
156 model = Node165 model = Node
157166
158167
=== added file 'src/maasserver/migrations/0043_unique_hostname_preparation.py'
--- src/maasserver/migrations/0043_unique_hostname_preparation.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/migrations/0043_unique_hostname_preparation.py 2012-11-16 13:58:29 +0000
@@ -0,0 +1,218 @@
1# -*- coding: utf-8 -*-
2import datetime
3
4from django.db import models
5from django.db.models import Count
6from south.db import db
7from south.v2 import DataMigration
8
9
10class Migration(DataMigration):
11
12 def forwards(self, orm):
13 # Find the nodes with duplicated hostnames.
14 duplicated_hostnames = orm['maasserver.node'].objects.values_list(
15 'hostname', flat=True).annotate(
16 hostname_count=Count('hostname')).exclude(hostname_count=1)
17 # Rename the nodes with duplicated hostnames.
18 for duplicated_hostname in duplicated_hostnames:
19 nodes_with_duplicated_hostnames = (
20 orm['maasserver.node'].objects.filter(
21 hostname=duplicated_hostname))
22 # Rename all the nodes but one.
23 for node in nodes_with_duplicated_hostnames[1:]:
24 number = 1
25 while True:
26 new_hostname = '%s-%d' % (node.hostname, number)
27 if not orm['maasserver.node'].objects.filter(hostname=new_hostname).exists():
28 node.hostname = new_hostname
29 node.save()
30 break
31 number += 1
32
33
34 def backwards(self, orm):
35 pass
36
37 models = {
38 'auth.group': {
39 'Meta': {'object_name': 'Group'},
40 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
41 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
42 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
43 },
44 'auth.permission': {
45 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
46 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
47 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
48 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
49 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
50 },
51 'auth.user': {
52 'Meta': {'object_name': 'User'},
53 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
54 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}),
55 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
56 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
57 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
58 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
59 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
60 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
61 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
62 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
63 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
64 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
65 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
66 },
67 'contenttypes.contenttype': {
68 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
69 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
70 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
71 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
72 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
73 },
74 u'maasserver.bootimage': {
75 'Meta': {'unique_together': "((u'nodegroup', u'architecture', u'subarchitecture', u'release', u'purpose'),)", 'object_name': 'BootImage'},
76 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
77 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
78 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
79 'purpose': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
80 'release': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
81 'subarchitecture': ('django.db.models.fields.CharField', [], {'max_length': '255'})
82 },
83 u'maasserver.componenterror': {
84 'Meta': {'object_name': 'ComponentError'},
85 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
86 'created': ('django.db.models.fields.DateTimeField', [], {}),
87 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
88 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
89 'updated': ('django.db.models.fields.DateTimeField', [], {})
90 },
91 u'maasserver.config': {
92 'Meta': {'object_name': 'Config'},
93 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
94 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
95 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'})
96 },
97 u'maasserver.dhcplease': {
98 'Meta': {'object_name': 'DHCPLease'},
99 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
100 'ip': ('django.db.models.fields.IPAddressField', [], {'unique': 'True', 'max_length': '15'}),
101 'mac': ('maasserver.fields.MACAddressField', [], {}),
102 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"})
103 },
104 u'maasserver.filestorage': {
105 'Meta': {'object_name': 'FileStorage'},
106 'content': ('metadataserver.fields.BinaryField', [], {}),
107 'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
108 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
109 },
110 u'maasserver.macaddress': {
111 'Meta': {'object_name': 'MACAddress'},
112 'created': ('django.db.models.fields.DateTimeField', [], {}),
113 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
114 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}),
115 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}),
116 'updated': ('django.db.models.fields.DateTimeField', [], {})
117 },
118 u'maasserver.node': {
119 'Meta': {'object_name': 'Node'},
120 'after_commissioning_action': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
121 'architecture': ('django.db.models.fields.CharField', [], {'default': "u'i386/generic'", 'max_length': '31'}),
122 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
123 'created': ('django.db.models.fields.DateTimeField', [], {}),
124 'distro_series': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '10', 'null': 'True', 'blank': 'True'}),
125 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
126 'hardware_details': ('maasserver.fields.XMLField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
127 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
128 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
129 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
130 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
131 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}),
132 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
133 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
134 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}),
135 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}),
136 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-6b5652fe-2412-11e2-9eff-9c4e363b1c94'", 'unique': 'True', 'max_length': '41'}),
137 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}),
138 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Token']", 'null': 'True'}),
139 'updated': ('django.db.models.fields.DateTimeField', [], {})
140 },
141 u'maasserver.nodegroup': {
142 'Meta': {'object_name': 'NodeGroup'},
143 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}),
144 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Token']", 'unique': 'True'}),
145 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}),
146 'created': ('django.db.models.fields.DateTimeField', [], {}),
147 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
148 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
149 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
150 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
151 'updated': ('django.db.models.fields.DateTimeField', [], {}),
152 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'})
153 },
154 u'maasserver.nodegroupinterface': {
155 'Meta': {'unique_together': "((u'nodegroup', u'interface'),)", 'object_name': 'NodeGroupInterface'},
156 'broadcast_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
157 'created': ('django.db.models.fields.DateTimeField', [], {}),
158 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
159 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
160 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
161 'ip_range_high': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
162 'ip_range_low': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
163 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
164 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
165 'router_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
166 'subnet_mask': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
167 'updated': ('django.db.models.fields.DateTimeField', [], {})
168 },
169 u'maasserver.sshkey': {
170 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'},
171 'created': ('django.db.models.fields.DateTimeField', [], {}),
172 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
173 'key': ('django.db.models.fields.TextField', [], {}),
174 'updated': ('django.db.models.fields.DateTimeField', [], {}),
175 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
176 },
177 u'maasserver.tag': {
178 'Meta': {'object_name': 'Tag'},
179 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
180 'created': ('django.db.models.fields.DateTimeField', [], {}),
181 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
182 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
183 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
184 'updated': ('django.db.models.fields.DateTimeField', [], {})
185 },
186 u'maasserver.userprofile': {
187 'Meta': {'object_name': 'UserProfile'},
188 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
189 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
190 },
191 'piston.consumer': {
192 'Meta': {'object_name': 'Consumer'},
193 'description': ('django.db.models.fields.TextField', [], {}),
194 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
195 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
196 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
197 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
198 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}),
199 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': "orm['auth.User']"})
200 },
201 'piston.token': {
202 'Meta': {'object_name': 'Token'},
203 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
204 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
205 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Consumer']"}),
206 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
207 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
208 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
209 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
210 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1351767230L'}),
211 'token_type': ('django.db.models.fields.IntegerField', [], {}),
212 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': "orm['auth.User']"}),
213 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'})
214 }
215 }
216
217 complete_apps = ['maasserver']
218 symmetrical = True
0219
=== added file 'src/maasserver/migrations/0044_node_hostname_unique.py'
--- src/maasserver/migrations/0044_node_hostname_unique.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/migrations/0044_node_hostname_unique.py 2012-11-16 13:58:29 +0000
@@ -0,0 +1,201 @@
1# -*- coding: utf-8 -*-
2import datetime
3
4from django.db import models
5from south.db import db
6from south.v2 import SchemaMigration
7
8
9class Migration(SchemaMigration):
10
11 def forwards(self, orm):
12 # Adding unique constraint on 'Node', fields ['hostname']
13 db.create_unique(u'maasserver_node', ['hostname'])
14
15
16 def backwards(self, orm):
17 # Removing unique constraint on 'Node', fields ['hostname']
18 db.delete_unique(u'maasserver_node', ['hostname'])
19
20
21 models = {
22 'auth.group': {
23 'Meta': {'object_name': 'Group'},
24 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
25 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
26 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
27 },
28 'auth.permission': {
29 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
30 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
31 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
32 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
33 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
34 },
35 'auth.user': {
36 'Meta': {'object_name': 'User'},
37 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
38 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}),
39 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
40 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
41 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
42 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
43 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
44 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
45 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
46 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
47 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
48 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
49 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
50 },
51 'contenttypes.contenttype': {
52 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
53 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
54 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
55 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
56 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
57 },
58 u'maasserver.bootimage': {
59 'Meta': {'unique_together': "((u'nodegroup', u'architecture', u'subarchitecture', u'release', u'purpose'),)", 'object_name': 'BootImage'},
60 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
61 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
62 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
63 'purpose': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
64 'release': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
65 'subarchitecture': ('django.db.models.fields.CharField', [], {'max_length': '255'})
66 },
67 u'maasserver.componenterror': {
68 'Meta': {'object_name': 'ComponentError'},
69 'component': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
70 'created': ('django.db.models.fields.DateTimeField', [], {}),
71 'error': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
72 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73 'updated': ('django.db.models.fields.DateTimeField', [], {})
74 },
75 u'maasserver.config': {
76 'Meta': {'object_name': 'Config'},
77 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
78 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
79 'value': ('maasserver.fields.JSONObjectField', [], {'null': 'True'})
80 },
81 u'maasserver.dhcplease': {
82 'Meta': {'object_name': 'DHCPLease'},
83 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
84 'ip': ('django.db.models.fields.IPAddressField', [], {'unique': 'True', 'max_length': '15'}),
85 'mac': ('maasserver.fields.MACAddressField', [], {}),
86 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"})
87 },
88 u'maasserver.filestorage': {
89 'Meta': {'object_name': 'FileStorage'},
90 'content': ('metadataserver.fields.BinaryField', [], {}),
91 'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
92 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
93 },
94 u'maasserver.macaddress': {
95 'Meta': {'object_name': 'MACAddress'},
96 'created': ('django.db.models.fields.DateTimeField', [], {}),
97 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
98 'mac_address': ('maasserver.fields.MACAddressField', [], {'unique': 'True'}),
99 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.Node']"}),
100 'updated': ('django.db.models.fields.DateTimeField', [], {})
101 },
102 u'maasserver.node': {
103 'Meta': {'object_name': 'Node'},
104 'after_commissioning_action': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
105 'architecture': ('django.db.models.fields.CharField', [], {'default': "u'i386/generic'", 'max_length': '31'}),
106 'cpu_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
107 'created': ('django.db.models.fields.DateTimeField', [], {}),
108 'distro_series': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '10', 'null': 'True', 'blank': 'True'}),
109 'error': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
110 'hardware_details': ('maasserver.fields.XMLField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
111 'hostname': ('django.db.models.fields.CharField', [], {'default': "u''", 'unique': 'True', 'max_length': '255', 'blank': 'True'}),
112 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
113 'memory': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
114 'netboot': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
115 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']", 'null': 'True'}),
116 'owner': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
117 'power_parameters': ('maasserver.fields.JSONObjectField', [], {'default': "u''", 'blank': 'True'}),
118 'power_type': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '10', 'blank': 'True'}),
119 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '10'}),
120 'system_id': ('django.db.models.fields.CharField', [], {'default': "u'node-763aa1fc-2412-11e2-be98-9c4e363b1c94'", 'unique': 'True', 'max_length': '41'}),
121 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['maasserver.Tag']", 'symmetrical': 'False'}),
122 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Token']", 'null': 'True'}),
123 'updated': ('django.db.models.fields.DateTimeField', [], {})
124 },
125 u'maasserver.nodegroup': {
126 'Meta': {'object_name': 'NodeGroup'},
127 'api_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '18'}),
128 'api_token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Token']", 'unique': 'True'}),
129 'cluster_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100', 'blank': 'True'}),
130 'created': ('django.db.models.fields.DateTimeField', [], {}),
131 'dhcp_key': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
132 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
133 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
134 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
135 'updated': ('django.db.models.fields.DateTimeField', [], {}),
136 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'})
137 },
138 u'maasserver.nodegroupinterface': {
139 'Meta': {'unique_together': "((u'nodegroup', u'interface'),)", 'object_name': 'NodeGroupInterface'},
140 'broadcast_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
141 'created': ('django.db.models.fields.DateTimeField', [], {}),
142 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
143 'interface': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'blank': 'True'}),
144 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
145 'ip_range_high': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
146 'ip_range_low': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
147 'management': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
148 'nodegroup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['maasserver.NodeGroup']"}),
149 'router_ip': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
150 'subnet_mask': ('django.db.models.fields.GenericIPAddressField', [], {'default': 'None', 'max_length': '39', 'null': 'True', 'blank': 'True'}),
151 'updated': ('django.db.models.fields.DateTimeField', [], {})
152 },
153 u'maasserver.sshkey': {
154 'Meta': {'unique_together': "((u'user', u'key'),)", 'object_name': 'SSHKey'},
155 'created': ('django.db.models.fields.DateTimeField', [], {}),
156 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
157 'key': ('django.db.models.fields.TextField', [], {}),
158 'updated': ('django.db.models.fields.DateTimeField', [], {}),
159 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
160 },
161 u'maasserver.tag': {
162 'Meta': {'object_name': 'Tag'},
163 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
164 'created': ('django.db.models.fields.DateTimeField', [], {}),
165 'definition': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
166 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
167 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
168 'updated': ('django.db.models.fields.DateTimeField', [], {})
169 },
170 u'maasserver.userprofile': {
171 'Meta': {'object_name': 'UserProfile'},
172 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
173 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
174 },
175 'piston.consumer': {
176 'Meta': {'object_name': 'Consumer'},
177 'description': ('django.db.models.fields.TextField', [], {}),
178 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
179 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
180 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
181 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
182 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '16'}),
183 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'consumers'", 'null': 'True', 'to': "orm['auth.User']"})
184 },
185 'piston.token': {
186 'Meta': {'object_name': 'Token'},
187 'callback': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
188 'callback_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
189 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['piston.Consumer']"}),
190 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
191 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
192 'key': ('django.db.models.fields.CharField', [], {'max_length': '18'}),
193 'secret': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
194 'timestamp': ('django.db.models.fields.IntegerField', [], {'default': '1351767248L'}),
195 'token_type': ('django.db.models.fields.IntegerField', [], {}),
196 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tokens'", 'null': 'True', 'to': "orm['auth.User']"}),
197 'verifier': ('django.db.models.fields.CharField', [], {'max_length': '10'})
198 }
199 }
200
201 complete_apps = ['maasserver']
0\ No newline at end of file202\ No newline at end of file
1203
=== modified file 'src/maasserver/models/node.py'
--- src/maasserver/models/node.py 2012-11-16 07:43:42 +0000
+++ src/maasserver/models/node.py 2012-11-16 13:58:29 +0000
@@ -428,6 +428,7 @@
428 :ivar power_type: The :class:`POWER_TYPE` that determines how this428 :ivar power_type: The :class:`POWER_TYPE` that determines how this
429 node will be powered on. If not given, the default will be used as429 node will be powered on. If not given, the default will be used as
430 configured in the `node_power_type` setting.430 configured in the `node_power_type` setting.
431 :ivar nodegroup: The `NodeGroup` this `Node` belongs to.
431 :ivar tags: The list of :class:`Tag`s associated with this `Node`.432 :ivar tags: The list of :class:`Tag`s associated with this `Node`.
432 :ivar objects: The :class:`NodeManager`.433 :ivar objects: The :class:`NodeManager`.
433434
@@ -440,7 +441,7 @@
440 max_length=41, unique=True, default=generate_node_system_id,441 max_length=41, unique=True, default=generate_node_system_id,
441 editable=False)442 editable=False)
442443
443 hostname = CharField(max_length=255, default='', blank=True)444 hostname = CharField(max_length=255, default='', blank=True, unique=True)
444445
445 status = IntegerField(446 status = IntegerField(
446 max_length=10, choices=NODE_STATUS_CHOICES, editable=False,447 max_length=10, choices=NODE_STATUS_CHOICES, editable=False,
447448
=== modified file 'src/maasserver/templates/maasserver/node_edit.html'
--- src/maasserver/templates/maasserver/node_edit.html 2012-07-10 16:03:27 +0000
+++ src/maasserver/templates/maasserver/node_edit.html 2012-11-16 13:58:29 +0000
@@ -30,6 +30,7 @@
30{% endblock %}30{% endblock %}
3131
32{% block content %}32{% block content %}
33 <div id="node-edit" class="block size7">
33 <form action="." method="post" class="block auto-width">34 <form action="." method="post" class="block auto-width">
34 {% csrf_token %}35 {% csrf_token %}
35 <ul>36 <ul>
@@ -62,4 +63,5 @@
62 <input type="submit" value="Save node" class="right" />63 <input type="submit" value="Save node" class="right" />
63 <a class="link-button" href="{% url 'node-view' node.system_id %}">Cancel</a>64 <a class="link-button" href="{% url 'node-view' node.system_id %}">Cancel</a>
64 </form>65 </form>
66 </div>
65{% endblock %}67{% endblock %}
6668
=== modified file 'src/maasserver/templates/maasserver/node_view.html'
--- src/maasserver/templates/maasserver/node_view.html 2012-10-05 17:42:12 +0000
+++ src/maasserver/templates/maasserver/node_view.html 2012-11-16 13:58:29 +0000
@@ -1,8 +1,8 @@
1{% extends "maasserver/base.html" %}1{% extends "maasserver/base.html" %}
22
3{% block nav-active-settings %}active{% endblock %}3{% block nav-active-settings %}active{% endblock %}
4{% block title %}Node: {{ node.hostname }}{% endblock %}4{% block title %}Node: {{ node.fqdn }}{% endblock %}
5{% block page-title %}Node: {{ node.hostname }}{% endblock %}5{% block page-title %}Node: {{ node.fqdn }}{% endblock %}
6{% block layout-modifiers %}sidebar{% endblock %}6{% block layout-modifiers %}sidebar{% endblock %}
77
8{% block sidebar %}8{% block sidebar %}
@@ -39,8 +39,8 @@
39{% block content %}39{% block content %}
40 <ul class="data-list">40 <ul class="data-list">
41 <li class="block size3 first">41 <li class="block size3 first">
42 <h4>Hostname</h4>42 <h4><acronym title="Fully Qualified Domain Name">FQDN</acronym></h4>
43 <span>{{ node.hostname }}</span>43 <span>{{ node.fqdn }}</span>
44 </li>44 </li>
45 <li class="block size3">45 <li class="block size3">
46 <h4>MAC addresses</h4>46 <h4>MAC addresses</h4>
4747
=== modified file 'src/maasserver/templates/maasserver/nodes_listing.html'
--- src/maasserver/templates/maasserver/nodes_listing.html 2012-10-10 08:13:01 +0000
+++ src/maasserver/templates/maasserver/nodes_listing.html 2012-11-16 13:58:29 +0000
@@ -2,19 +2,22 @@
2 <table class="list">2 <table class="list">
3 <thead>3 <thead>
4 <tr>4 <tr>
5 <th>MAC</th>5 <th><acronym title="Fully Qualified Domain Name">FQDN</acronym></th>
6 <th>Status</th>6 <th><acronym
7 title="Media Access Control addresses">MAC</acronym></th>
7 </tr>8 </tr>
8 </thead>9 </thead>
9 {% for node in node_list %}10 {% for node in node_list %}
10 <tr class="node {% cycle 'even' 'odd' %}">11 <tr class="node {% cycle 'even' 'odd' %}">
11 <td>12 <td>
12 <a href="{% url 'node-view' node.system_id %}">13 <a href="{% url 'node-view' node.system_id %}">
13 {% for macaddress in node.macaddress_set.all reversed %}14 {{ node.fqdn }}
14 {{ macaddress }}{% if not forloop.last %},{% endif %}
15 {% endfor %}
16 </a>15 </a>
17 ({{ node.hostname }})16 </td>
17 <td>
18 {% for macaddress in node.macaddress_set.all reversed %}
19 {{ macaddress }}{% if not forloop.last %},{% endif %}
20 {% endfor %}
18 </td>21 </td>
19 <td>{{ node.display_status }}</td>22 <td>{{ node.display_status }}</td>
20 </tr>23 </tr>
2124
=== modified file 'src/maasserver/testing/factory.py'
--- src/maasserver/testing/factory.py 2012-11-08 09:14:58 +0000
+++ src/maasserver/testing/factory.py 2012-11-16 13:58:29 +0000
@@ -96,11 +96,11 @@
96 finally:96 finally:
97 NODE_TRANSITIONS[None] = valid_initial_states97 NODE_TRANSITIONS[None] = valid_initial_states
9898
99 def make_node(self, mac=False, hostname='', set_hostname=False,99 def make_node(self, mac=False, hostname=None, status=None,
100 status=None, architecture=ARCHITECTURE.i386, updated=None,100 architecture=ARCHITECTURE.i386, updated=None,
101 created=None, nodegroup=None, **kwargs):101 created=None, nodegroup=None, **kwargs):
102 # hostname=None is a valid value, hence the set_hostname trick.102 # hostname=None is a valid value, hence the set_hostname trick.
103 if hostname is '' and set_hostname:103 if hostname is None:
104 hostname = self.getRandomString(20)104 hostname = self.getRandomString(20)
105 if status is None:105 if status is None:
106 status = NODE_STATUS.DEFAULT_STATUS106 status = NODE_STATUS.DEFAULT_STATUS
107107
=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py 2012-11-16 07:43:42 +0000
+++ src/maasserver/tests/test_api.py 2012-11-16 13:58:29 +0000
@@ -1170,7 +1170,7 @@
11701170
1171 def test_GET_returns_node(self):1171 def test_GET_returns_node(self):
1172 # The api allows for fetching a single Node (using system_id).1172 # The api allows for fetching a single Node (using system_id).
1173 node = factory.make_node(set_hostname=True)1173 node = factory.make_node()
1174 response = self.client.get(self.get_node_uri(node))1174 response = self.client.get(self.get_node_uri(node))
11751175
1176 self.assertEqual(httplib.OK, response.status_code)1176 self.assertEqual(httplib.OK, response.status_code)
@@ -1179,7 +1179,7 @@
1179 self.assertEqual(node.system_id, parsed_result['system_id'])1179 self.assertEqual(node.system_id, parsed_result['system_id'])
11801180
1181 def test_GET_returns_associated_tag(self):1181 def test_GET_returns_associated_tag(self):
1182 node = factory.make_node(set_hostname=True)1182 node = factory.make_node()
1183 tag = factory.make_tag()1183 tag = factory.make_tag()
1184 node.tags.add(tag)1184 node.tags.add(tag)
1185 response = self.client.get(self.get_node_uri(node))1185 response = self.client.get(self.get_node_uri(node))
@@ -1424,6 +1424,15 @@
1424 self.assertEqual(0, Node.objects.filter(hostname='diane').count())1424 self.assertEqual(0, Node.objects.filter(hostname='diane').count())
1425 self.assertEqual(1, Node.objects.filter(hostname='francis').count())1425 self.assertEqual(1, Node.objects.filter(hostname='francis').count())
14261426
1427 def test_PUT_omitted_hostname(self):
1428 hostname = factory.make_name('hostname')
1429 node = factory.make_node(hostname=hostname, owner=self.logged_in_user)
1430 response = self.client.put(
1431 self.get_node_uri(node),
1432 {'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES)})
1433 self.assertEqual(httplib.OK, response.status_code, response.content)
1434 self.assertTrue(Node.objects.filter(hostname=hostname).exists())
1435
1427 def test_PUT_ignores_unknown_fields(self):1436 def test_PUT_ignores_unknown_fields(self):
1428 node = factory.make_node(1437 node = factory.make_node(
1429 owner=self.logged_in_user,1438 owner=self.logged_in_user,
@@ -1677,7 +1686,7 @@
1677 def test_DELETE_deletes_node(self):1686 def test_DELETE_deletes_node(self):
1678 # The api allows to delete a Node.1687 # The api allows to delete a Node.
1679 self.become_admin()1688 self.become_admin()
1680 node = factory.make_node(set_hostname=True, owner=self.logged_in_user)1689 node = factory.make_node(owner=self.logged_in_user)
1681 system_id = node.system_id1690 system_id = node.system_id
1682 response = self.client.delete(self.get_node_uri(node))1691 response = self.client.delete(self.get_node_uri(node))
16831692
@@ -1699,14 +1708,14 @@
16991708
1700 def test_DELETE_deletes_node_fails_if_not_admin(self):1709 def test_DELETE_deletes_node_fails_if_not_admin(self):
1701 # Only superusers can delete nodes.1710 # Only superusers can delete nodes.
1702 node = factory.make_node(set_hostname=True, owner=self.logged_in_user)1711 node = factory.make_node(owner=self.logged_in_user)
1703 response = self.client.delete(self.get_node_uri(node))1712 response = self.client.delete(self.get_node_uri(node))
17041713
1705 self.assertEqual(httplib.FORBIDDEN, response.status_code)1714 self.assertEqual(httplib.FORBIDDEN, response.status_code)
17061715
1707 def test_DELETE_forbidden_without_edit_permission(self):1716 def test_DELETE_forbidden_without_edit_permission(self):
1708 # A user without the edit permission cannot delete a Node.1717 # A user without the edit permission cannot delete a Node.
1709 node = factory.make_node(set_hostname=True)1718 node = factory.make_node()
1710 response = self.client.delete(self.get_node_uri(node))1719 response = self.client.delete(self.get_node_uri(node))
17111720
1712 self.assertEqual(httplib.FORBIDDEN, response.status_code)1721 self.assertEqual(httplib.FORBIDDEN, response.status_code)
@@ -1771,8 +1780,7 @@
1771 # The api allows for fetching the list of Nodes.1780 # The api allows for fetching the list of Nodes.
1772 node1 = factory.make_node()1781 node1 = factory.make_node()
1773 node2 = factory.make_node(1782 node2 = factory.make_node(
1774 set_hostname=True, status=NODE_STATUS.ALLOCATED,1783 status=NODE_STATUS.ALLOCATED, owner=self.logged_in_user)
1775 owner=self.logged_in_user)
1776 response = self.client.get(self.get_uri('nodes/'), {'op': 'list'})1784 response = self.client.get(self.get_uri('nodes/'), {'op': 'list'})
1777 parsed_result = json.loads(response.content)1785 parsed_result = json.loads(response.content)
17781786
17791787
=== modified file 'src/maasserver/tests/test_dhcplease.py'
--- src/maasserver/tests/test_dhcplease.py 2012-10-30 15:15:30 +0000
+++ src/maasserver/tests/test_dhcplease.py 2012-11-16 13:58:29 +0000
@@ -168,7 +168,7 @@
168 expected_mapping = {}168 expected_mapping = {}
169 for i in range(3):169 for i in range(3):
170 node = factory.make_node(170 node = factory.make_node(
171 nodegroup=nodegroup, set_hostname=True)171 nodegroup=nodegroup)
172 mac = factory.make_mac_address(node=node)172 mac = factory.make_mac_address(node=node)
173 factory.make_mac_address(node=node)173 factory.make_mac_address(node=node)
174 lease = factory.make_dhcp_lease(174 lease = factory.make_dhcp_lease(
@@ -193,7 +193,7 @@
193 def test_get_hostname_ip_mapping_considers_only_first_mac(self):193 def test_get_hostname_ip_mapping_considers_only_first_mac(self):
194 nodegroup = factory.make_node_group()194 nodegroup = factory.make_node_group()
195 node = factory.make_node(195 node = factory.make_node(
196 nodegroup=nodegroup, set_hostname=True)196 nodegroup=nodegroup)
197 factory.make_mac_address(node=node)197 factory.make_mac_address(node=node)
198 second_mac = factory.make_mac_address(node=node)198 second_mac = factory.make_mac_address(node=node)
199 # Create a lease for the second MAC Address.199 # Create a lease for the second MAC Address.
@@ -205,7 +205,7 @@
205 def test_get_hostname_ip_mapping_considers_given_nodegroup(self):205 def test_get_hostname_ip_mapping_considers_given_nodegroup(self):
206 nodegroup = factory.make_node_group()206 nodegroup = factory.make_node_group()
207 node = factory.make_node(207 node = factory.make_node(
208 nodegroup=nodegroup, set_hostname=True)208 nodegroup=nodegroup)
209 mac = factory.make_mac_address(node=node)209 mac = factory.make_mac_address(node=node)
210 factory.make_dhcp_lease(210 factory.make_dhcp_lease(
211 nodegroup=nodegroup, mac=mac.mac_address)211 nodegroup=nodegroup, mac=mac.mac_address)
212212
=== modified file 'src/maasserver/tests/test_dns.py'
--- src/maasserver/tests/test_dns.py 2012-10-11 01:17:24 +0000
+++ src/maasserver/tests/test_dns.py 2012-11-16 13:58:29 +0000
@@ -157,7 +157,7 @@
157 management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)157 management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)
158 interface = nodegroup.get_managed_interface()158 interface = nodegroup.get_managed_interface()
159 node = factory.make_node(159 node = factory.make_node(
160 nodegroup=nodegroup, set_hostname=True)160 nodegroup=nodegroup)
161 mac = factory.make_mac_address(node=node)161 mac = factory.make_mac_address(node=node)
162 ips = IPRange(interface.ip_range_low, interface.ip_range_high)162 ips = IPRange(interface.ip_range_low, interface.ip_range_high)
163 lease_ip = str(islice(ips, lease_number, lease_number + 1).next())163 lease_ip = str(islice(ips, lease_number, lease_number + 1).next())
164164
=== modified file 'src/maasserver/tests/test_forms.py'
--- src/maasserver/tests/test_forms.py 2012-11-09 18:12:36 +0000
+++ src/maasserver/tests/test_forms.py 2012-11-16 13:58:29 +0000
@@ -381,18 +381,6 @@
381 form.save()381 form.save()
382 self.assertEqual(old_name, reload_object(node).hostname)382 self.assertEqual(old_name, reload_object(node).hostname)
383383
384 def test_AdminNodeForm_accepts_omitted_hostname_on_allocated_node(self):
385 node = factory.make_node(status=NODE_STATUS.ALLOCATED)
386 old_name = node.hostname
387 form = AdminNodeForm(
388 data={
389 'architecture': node.architecture,
390 },
391 instance=node)
392 self.assertTrue(form.is_valid())
393 form.save()
394 self.assertEqual(old_name, reload_object(node).hostname)
395
396 def test_remove_None_values_removes_None_values_in_dict(self):384 def test_remove_None_values_removes_None_values_in_dict(self):
397 random_input = factory.getRandomString()385 random_input = factory.getRandomString()
398 self.assertEqual(386 self.assertEqual(
399387
=== modified file 'src/maasserver/tests/test_node.py'
--- src/maasserver/tests/test_node.py 2012-11-16 07:43:42 +0000
+++ src/maasserver/tests/test_node.py 2012-11-16 13:58:29 +0000
@@ -313,7 +313,7 @@
313 node: node.get_effective_power_type()313 node: node.get_effective_power_type()
314 for node in nodes}314 for node in nodes}
315 started_nodes = Node.objects.start_nodes(315 started_nodes = Node.objects.start_nodes(
316 list(node_power_types.keys()), user)316 [node.system_id for node in list(node_power_types.keys())], user)
317 successful_types = [node_power_types[node] for node in started_nodes]317 successful_types = [node_power_types[node] for node in started_nodes]
318 self.assertItemsEqual(configless_power_types, successful_types)318 self.assertItemsEqual(configless_power_types, successful_types)
319319
@@ -636,8 +636,7 @@
636 status = NODE_STATUS.READY636 status = NODE_STATUS.READY
637 else:637 else:
638 status = NODE_STATUS.ALLOCATED638 status = NODE_STATUS.ALLOCATED
639 return factory.make_node(639 return factory.make_node(status=status, owner=user, **kwargs)
640 set_hostname=True, status=status, owner=user, **kwargs)
641640
642 def make_node_with_mac(self, user=None, **kwargs):641 def make_node_with_mac(self, user=None, **kwargs):
643 node = self.make_node(user, **kwargs)642 node = self.make_node(user, **kwargs)
644643
=== modified file 'src/maasserver/tests/test_node_constraint_filter.py'
--- src/maasserver/tests/test_node_constraint_filter.py 2012-10-11 06:59:33 +0000
+++ src/maasserver/tests/test_node_constraint_filter.py 2012-11-16 13:58:29 +0000
@@ -60,8 +60,8 @@
60 self.assertConstrainedNodes([node1, node2], {})60 self.assertConstrainedNodes([node1, node2], {})
6161
62 def test_hostname(self):62 def test_hostname(self):
63 node1 = factory.make_node(set_hostname=True)63 node1 = factory.make_node()
64 node2 = factory.make_node(set_hostname=True)64 node2 = factory.make_node()
65 self.assertConstrainedNodes([node1], {'hostname': node1.hostname})65 self.assertConstrainedNodes([node1], {'hostname': node1.hostname})
66 self.assertConstrainedNodes([node2], {'hostname': node2.hostname})66 self.assertConstrainedNodes([node2], {'hostname': node2.hostname})
67 self.assertConstrainedNodes([], {'hostname': 'unknown-name'})67 self.assertConstrainedNodes([], {'hostname': 'unknown-name'})
6868
=== modified file 'src/maasserver/tests/test_views_nodes.py'
--- src/maasserver/tests/test_views_nodes.py 2012-10-17 05:20:13 +0000
+++ src/maasserver/tests/test_views_nodes.py 2012-11-16 13:58:29 +0000
@@ -25,6 +25,8 @@
25 ARCHITECTURE_CHOICES,25 ARCHITECTURE_CHOICES,
26 NODE_AFTER_COMMISSIONING_ACTION,26 NODE_AFTER_COMMISSIONING_ACTION,
27 NODE_STATUS,27 NODE_STATUS,
28 NODEGROUP_STATUS,
29 NODEGROUPINTERFACE_MANAGEMENT,
28 )30 )
29from maasserver.exceptions import (31from maasserver.exceptions import (
30 InvalidConstraint,32 InvalidConstraint,
@@ -79,6 +81,21 @@
79 enlist_preseed_link = reverse('enlist-preseed-view')81 enlist_preseed_link = reverse('enlist-preseed-view')
80 self.assertIn(enlist_preseed_link, get_content_links(response))82 self.assertIn(enlist_preseed_link, get_content_links(response))
8183
84 def test_node_list_displays_fqdn_dns_not_managed(self):
85 nodes = [factory.make_node() for i in range(3)]
86 response = self.client.get(reverse('node-list'))
87 node_fqdns = [node.fqdn for node in nodes]
88 self.assertThat(response.content, ContainsAll(node_fqdns))
89
90 def test_node_list_displays_fqdn_dns_managed(self):
91 nodegroup = factory.make_node_group(
92 status=NODEGROUP_STATUS.ACCEPTED,
93 management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)
94 nodes = [factory.make_node(nodegroup=nodegroup) for i in range(3)]
95 response = self.client.get(reverse('node-list'))
96 node_fqdns = [node.fqdn for node in nodes]
97 self.assertThat(response.content, ContainsAll(node_fqdns))
98
82 def test_node_list_displays_sorted_list_of_nodes(self):99 def test_node_list_displays_sorted_list_of_nodes(self):
83 # Nodes are sorted on the node list page, newest first.100 # Nodes are sorted on the node list page, newest first.
84 nodes = [factory.make_node() for i in range(3)]101 nodes = [factory.make_node() for i in range(3)]
@@ -493,7 +510,7 @@
493 def test_preseedview_node_displays_message_if_commissioning(self):510 def test_preseedview_node_displays_message_if_commissioning(self):
494 node = factory.make_node(511 node = factory.make_node(
495 owner=self.logged_in_user, status=NODE_STATUS.COMMISSIONING,512 owner=self.logged_in_user, status=NODE_STATUS.COMMISSIONING,
496 set_hostname=True)513 )
497 node_preseed_link = reverse('node-preseed-view', args=[node.system_id])514 node_preseed_link = reverse('node-preseed-view', args=[node.system_id])
498 response = self.client.get(node_preseed_link)515 response = self.client.get(node_preseed_link)
499 self.assertThat(516 self.assertThat(
500517
=== modified file 'src/maasserver/tests/test_views_tags.py'
--- src/maasserver/tests/test_views_tags.py 2012-11-07 11:32:16 +0000
+++ src/maasserver/tests/test_views_tags.py 2012-11-16 13:58:29 +0000
@@ -15,15 +15,11 @@
15from django.core.urlresolvers import reverse15from django.core.urlresolvers import reverse
16from lxml.etree import XPath16from lxml.etree import XPath
17from lxml.html import fromstring17from lxml.html import fromstring
18from maastesting.matchers import ContainsAll18from maasserver.testing import get_content_links
19from maasserver.testing import (
20 get_content_links,
21 )
22from maasserver.testing.factory import factory19from maasserver.testing.factory import factory
23from maasserver.testing.testcase import (20from maasserver.testing.testcase import LoggedInTestCase
24 LoggedInTestCase,
25 )
26from maasserver.views import tags as tags_views21from maasserver.views import tags as tags_views
22from maastesting.matchers import ContainsAll
2723
2824
29class TagViewsTest(LoggedInTestCase):25class TagViewsTest(LoggedInTestCase):
@@ -37,12 +33,12 @@
37 response = self.client.get(tag_link)33 response = self.client.get(tag_link)
38 doc = fromstring(response.content)34 doc = fromstring(response.content)
39 content_text = doc.cssselect('#content')[0].text_content()35 content_text = doc.cssselect('#content')[0].text_content()
40 self.assertThat(content_text,36 self.assertThat(
41 ContainsAll([tag.comment, tag.definition]))37 content_text, ContainsAll([tag.comment, tag.definition]))
4238
43 def test_view_tag_includes_node_links(self):39 def test_view_tag_includes_node_links(self):
44 tag = factory.make_tag()40 tag = factory.make_tag()
45 node = factory.make_node(set_hostname=True)41 node = factory.make_node()
46 node.tags.add(tag)42 node.tags.add(tag)
47 mac = factory.make_mac_address(node=node).mac_address43 mac = factory.make_mac_address(node=node).mac_address
48 tag_link = reverse('tag-view', args=[tag.name])44 tag_link = reverse('tag-view', args=[tag.name])
@@ -50,8 +46,8 @@
50 response = self.client.get(tag_link)46 response = self.client.get(tag_link)
51 doc = fromstring(response.content)47 doc = fromstring(response.content)
52 content_text = doc.cssselect('#content')[0].text_content()48 content_text = doc.cssselect('#content')[0].text_content()
53 self.assertThat(content_text,49 self.assertThat(
54 ContainsAll([mac, '(%s)' % node.hostname]))50 content_text, ContainsAll([mac, '%s' % node.hostname]))
55 self.assertNotIn(node.system_id, content_text)51 self.assertNotIn(node.system_id, content_text)
56 self.assertIn(node_link, get_content_links(response))52 self.assertIn(node_link, get_content_links(response))
5753
@@ -82,8 +78,8 @@
8278
83 def test_view_tag_hides_private_nodes(self):79 def test_view_tag_hides_private_nodes(self):
84 tag = factory.make_tag()80 tag = factory.make_tag()
85 node = factory.make_node(set_hostname=True)81 node = factory.make_node()
86 node2 = factory.make_node(owner=factory.make_user(), set_hostname=True)82 node2 = factory.make_node(owner=factory.make_user())
87 node.tags.add(tag)83 node.tags.add(tag)
88 node2.tags.add(tag)84 node2.tags.add(tag)
89 tag_link = reverse('tag-view', args=[tag.name])85 tag_link = reverse('tag-view', args=[tag.name])
9086
=== modified file 'src/maasserver/views/nodes.py'
--- src/maasserver/views/nodes.py 2012-10-17 05:20:13 +0000
+++ src/maasserver/views/nodes.py 2012-11-16 13:58:29 +0000
@@ -123,6 +123,8 @@
123 except InvalidConstraint as e:123 except InvalidConstraint as e:
124 self.query_error = e124 self.query_error = e
125 return Node.objects.none()125 return Node.objects.none()
126 nodes = nodes.prefetch_related('nodegroup')
127 nodes = nodes.prefetch_related('nodegroup__nodegroupinterface_set')
126 return nodes128 return nodes
127129
128 def get_context_data(self, **kwargs):130 def get_context_data(self, **kwargs):
129131
=== modified file 'src/maasserver/views/tags.py'
--- src/maasserver/views/tags.py 2012-11-07 11:32:16 +0000
+++ src/maasserver/views/tags.py 2012-11-16 13:58:29 +0000
@@ -33,9 +33,12 @@
33 return super(TagView, self).get(request, *args, **kwargs)33 return super(TagView, self).get(request, *args, **kwargs)
3434
35 def get_queryset(self):35 def get_queryset(self):
36 return Tag.objects.get_nodes(36 nodes = Tag.objects.get_nodes(
37 self.tag, user=self.request.user, prefetch_mac=True,37 self.tag, user=self.request.user, prefetch_mac=True,
38 ).order_by('-created')38 ).order_by('-created')
39 nodes = nodes.prefetch_related('nodegroup')
40 nodes = nodes.prefetch_related('nodegroup__nodegroupinterface_set')
41 return nodes
3942
40 def get_context_data(self, **kwargs):43 def get_context_data(self, **kwargs):
41 context = super(TagView, self).get_context_data(**kwargs)44 context = super(TagView, self).get_context_data(**kwargs)

Subscribers

People subscribed via source and target branches

to status/vote changes: