=== modified file 'src/maasserver/models/node.py'
--- src/maasserver/models/node.py 2014-12-09 17:13:52 +0000
+++ src/maasserver/models/node.py 2014-12-10 16:30:13 +0000
@@ -106,6 +106,7 @@
get_db_state,
strip_domain,
)
+from maasserver.utils.mac import get_vendor_for_mac
from metadataserver.enum import RESULT_TYPE
from netaddr import IPAddress
from piston.models import Token
@@ -1428,6 +1429,22 @@
return self.macaddress_set.first()
+ def get_pxe_mac_vendor(self):
+ """Return the vendor of the MAC address the node pxebooted from."""
+ pxe_mac = self.get_pxe_mac()
+ if pxe_mac is None:
+ return None
+ else:
+ return get_vendor_for_mac(pxe_mac.mac_address.get_raw())
+
+ def get_extra_macs(self):
+ """Get the MACs other that the one the node PXE booted from."""
+ pxe_mac = self.get_pxe_mac()
+ extra_macs = self.macaddress_set.all()
+ if pxe_mac is not None:
+ extra_macs = extra_macs.exclude(mac_address=pxe_mac.mac_address)
+ return extra_macs
+
def is_pxe_mac_on_managed_interface(self):
pxe_mac = self.get_pxe_mac()
if pxe_mac is not None:
=== modified file 'src/maasserver/models/tests/test_node.py'
--- src/maasserver/models/tests/test_node.py 2014-12-09 17:13:52 +0000
+++ src/maasserver/models/tests/test_node.py 2014-12-10 16:30:13 +0000
@@ -1828,6 +1828,37 @@
node.pxe_mac.delete()
self.assertThat(reload_object(node), Not(Is(None)))
+ def test_get_pxe_mac_vendor_returns_vendor(self):
+ node = factory.make_Node()
+ mac = factory.make_MACAddress(address='ec:a8:6b:fd:ae:3f', node=node)
+ node.pxe_mac = mac
+ node.save()
+ self.assertEqual(
+ "ELITEGROUP COMPUTER SYSTEMS CO., LTD.",
+ node.get_pxe_mac_vendor())
+
+ def test_get_extra_macs_returns_all_but_pxe_mac(self):
+ node = factory.make_Node()
+ macs = [factory.make_MACAddress(node=node) for _ in xrange(3)]
+ # Do not set the pxe mac to the first mac to make sure the pxe mac
+ # (and not the first created) is excluded from the list returned by
+ # `get_extra_macs`.
+ pxe_mac_index = 1
+ node.pxe_mac = macs[pxe_mac_index]
+ node.save()
+ del macs[pxe_mac_index]
+ self.assertItemsEqual(
+ macs,
+ node.get_extra_macs())
+
+ def test_get_extra_macs_returns_all_but_first_mac_if_no_pxe_mac(self):
+ node = factory.make_Node()
+ macs = [factory.make_MACAddress(node=node) for _ in xrange(3)]
+ node.save()
+ self.assertItemsEqual(
+ macs[1:],
+ node.get_extra_macs())
+
class TestNode_pxe_mac_on_managed_interface(MAASServerTestCase):
=== modified file 'src/maasserver/templates/maasserver/node_view.html'
--- src/maasserver/templates/maasserver/node_view.html 2014-12-09 22:31:25 +0000
+++ src/maasserver/templates/maasserver/node_view.html 2014-12-10 16:30:13 +0000
@@ -109,17 +109,11 @@
Network interfaces
- {% for mac in node.macaddress_set.all %}
- -
- {{ mac }}
- {% if mac.get_networks %}
- (on
- {# Per network interface, comma-separated list of networks. #}
- {% for network in mac.get_networks %}
-
- {{ network.name }}{% if not forloop.last %},
- {% endif %}{% endfor %}){% endif %}
-
+ {% with mac=node.get_pxe_mac %}
+ {% include "maasserver/node_view_mac_display.html" %}
+ {% endwith %}
+ {% for mac in node.get_extra_macs %}
+ {% include "maasserver/node_view_mac_display.html" %}
{% endfor %}
=== added file 'src/maasserver/templates/maasserver/node_view_mac_display.html'
--- src/maasserver/templates/maasserver/node_view_mac_display.html 1970-01-01 00:00:00 +0000
+++ src/maasserver/templates/maasserver/node_view_mac_display.html 2014-12-10 16:30:13 +0000
@@ -0,0 +1,10 @@
+
+ {{ mac }}
+ {% if mac.get_networks %}
+ (on
+ {# Per network interface, comma-separated list of networks. #}
+ {% for network in mac.get_networks %}
+
+ {{ network.name }}{% if not forloop.last %},
+ {% endif %}{% endfor %}){% endif %}
+
=== modified file 'src/maasserver/templates/maasserver/nodes_listing.html'
--- src/maasserver/templates/maasserver/nodes_listing.html 2014-11-05 15:10:12 +0000
+++ src/maasserver/templates/maasserver/nodes_listing.html 2014-12-10 16:30:13 +0000
@@ -87,15 +87,15 @@
{{ node.display_memory }} |
{{ node.display_storage }} |
-
- {{node.primary_mac}}
+
+ {{node.get_pxe_mac}}
- {% if node.extra_macs %}
+ {% if node.get_extra_macs %}
(+{{ node.extra_macs|length }})
+ ">(+{{ node.get_extra_macs|length }})
{% endif %}
|
=== added file 'src/maasserver/utils/mac.py'
--- src/maasserver/utils/mac.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/utils/mac.py 2014-12-10 16:30:13 +0000
@@ -0,0 +1,31 @@
+# Copyright 2014 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""MAC-related utilities."""
+
+from __future__ import (
+ absolute_import,
+ print_function,
+ unicode_literals,
+ )
+
+str = None
+
+__metaclass__ = type
+__all__ = [
+ 'get_vendor_for_mac',
+ ]
+
+from netaddr import (
+ EUI,
+ NotRegisteredError,
+ )
+
+
+def get_vendor_for_mac(mac):
+ """Return vendor for MAC."""
+ data = EUI(mac)
+ try:
+ return data.oui.registration().org
+ except NotRegisteredError:
+ return 'Unknown Vendor'
=== added file 'src/maasserver/utils/tests/test_mac.py'
--- src/maasserver/utils/tests/test_mac.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/utils/tests/test_mac.py 2014-12-10 16:30:13 +0000
@@ -0,0 +1,32 @@
+# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Test MAC utilities."""
+
+from __future__ import (
+ absolute_import,
+ print_function,
+ unicode_literals,
+ )
+
+str = None
+
+__metaclass__ = type
+__all__ = []
+
+
+from maasserver.utils.mac import get_vendor_for_mac
+from maastesting.testcase import MAASTestCase
+
+
+class TestGetVendorForMac(MAASTestCase):
+
+ def test_get_vendor_for_mac_returns_vendor(self):
+ self.assertEqual(
+ "ELITEGROUP COMPUTER SYSTEMS CO., LTD.",
+ get_vendor_for_mac('ec:a8:6b:fd:ae:3f'))
+
+ def test_get_vendor_for_mac_returns_error_message_if_unknown_mac(self):
+ self.assertEqual(
+ "Unknown Vendor",
+ get_vendor_for_mac('aa:bb:cc:dd:ee:ff'))
=== modified file 'src/maasserver/views/nodes.py'
--- src/maasserver/views/nodes.py 2014-12-08 20:47:25 +0000
+++ src/maasserver/views/nodes.py 2014-12-10 16:30:13 +0000
@@ -101,11 +101,7 @@
)
from metadataserver.enum import RESULT_TYPE
from metadataserver.models import NodeResult
-from netaddr import (
- EUI,
- IPAddress,
- NotRegisteredError,
- )
+from netaddr import IPAddress
from provisioningserver.tags import merge_details_cleanly
# Fields on the Node model that will be searched.
@@ -208,44 +204,6 @@
return mark_safe("[\n%s\n]" % ',\n'.join(names))
-def get_vendor_for_mac(mac):
- """Return vendor for MAC."""
- data = EUI(mac)
- try:
- return data.oui.registration().org
- except NotRegisteredError:
- return 'Unknown Vendor'
-
-
-def configure_mac(node):
- """Configure the node to have a primary_mac, primary_mac_vendor, and
- extra_macs attribute.
- """
- macs = node.macaddress_set.all()
- macs = sorted(macs, key=lambda mac: mac.created)
- macs = ['%s' % mac.mac_address for mac in macs]
- if len(macs) == 0:
- node.primary_mac = None
- node.primary_mac_vendor = None
- node.extra_macs = []
- else:
- node.primary_mac = macs[0]
- node.primary_mac_vendor = get_vendor_for_mac(node.primary_mac)
- node.extra_macs = macs[1:]
- return node
-
-
-def configure_macs(nodes):
- """Configures the each node in the query to have an "macs" attribute,
- that contains a list of macs, sorted by created.
-
- The list is structed to contain the MAC and its vendor.
- """
- for node in nodes:
- configure_mac(node)
- return nodes
-
-
def node_to_dict(node, event_log_count=0):
"""Convert `Node` to a dictionary.
@@ -256,6 +214,7 @@
owner = ""
else:
owner = '%s' % node.owner
+ pxe_mac = node.get_pxe_mac()
node_dict = dict(
id=node.id,
system_id=node.system_id,
@@ -271,9 +230,9 @@
power_state=node.power_state,
zone=node.zone.name,
zone_url=reverse('zone-view', args=[node.zone.name]),
- mac=node.primary_mac,
- vendor=node.primary_mac_vendor,
- macs=node.extra_macs,
+ mac=None if pxe_mac is None else pxe_mac.mac_address.get_raw(),
+ vendor=node.get_pxe_mac_vendor(),
+ macs=[mac.mac_address.get_raw() for mac in node.get_extra_macs()],
)
if event_log_count != 0:
# Add event information to the generated node dictionary. We exclude
@@ -532,7 +491,7 @@
if self.query:
nodes = self._search_nodes(nodes)
nodes = prefetch_nodes_listing(nodes)
- return configure_macs(nodes)
+ return nodes
def _prepare_sort_links(self):
"""Returns 2 dicts, with sort fields as keys and
@@ -600,7 +559,6 @@
nodes = Node.objects.get_nodes(
request.user, NODE_PERMISSION.VIEW, ids=match_ids)
nodes = prefetch_nodes_listing(nodes)
- nodes = configure_macs(nodes)
nodes = [node_to_dict(node) for node in nodes]
return HttpResponse(json.dumps(nodes), mimetype='application/json')
@@ -857,7 +815,6 @@
def handle_ajax_request(self, request, *args, **kwargs):
"""JSON response to update the node view."""
node = self.get_object()
- node = configure_mac(node)
node = node_to_dict(
node, event_log_count=self.number_of_events_shown)
node['action_view'] = self.render_node_actions(request)
=== modified file 'src/maasserver/views/tags.py'
--- src/maasserver/views/tags.py 2014-08-13 21:49:35 +0000
+++ src/maasserver/views/tags.py 2014-12-10 16:30:13 +0000
@@ -22,10 +22,7 @@
Tag,
)
from maasserver.views import PaginatedListView
-from maasserver.views.nodes import (
- configure_macs,
- prefetch_nodes_listing,
- )
+from maasserver.views.nodes import prefetch_nodes_listing
class TagView(PaginatedListView):
@@ -47,7 +44,7 @@
from_nodes=self.tag.node_set.all())
nodes = nodes.order_by('-created')
nodes = prefetch_nodes_listing(nodes)
- return configure_macs(nodes)
+ return nodes
def get_context_data(self, **kwargs):
context = super(TagView, self).get_context_data(**kwargs)
=== modified file 'src/maasserver/views/tests/test_nodes.py'
--- src/maasserver/views/tests/test_nodes.py 2014-12-08 20:47:25 +0000
+++ src/maasserver/views/tests/test_nodes.py 2014-12-10 16:30:13 +0000
@@ -86,8 +86,6 @@
from maasserver.utils.orm import get_one
from maasserver.views import nodes as nodes_views
from maasserver.views.nodes import (
- configure_mac,
- configure_macs,
event_to_dict,
message_from_form_stats,
node_to_dict,
@@ -118,8 +116,7 @@
class TestHelpers(MAASServerTestCase):
def test_node_to_dict_keys(self):
- node = factory.make_Node()
- node = configure_mac(node)
+ node = factory.make_Node(mac=True)
self.assertThat(
node_to_dict(node),
ContainsAll([
@@ -129,7 +126,6 @@
def test_node_to_dict_values(self):
node = factory.make_Node(mac=True)
- node = configure_mac(node)
dict_node = node_to_dict(node)
self.expectThat(dict_node['id'], Equals(node.id))
self.expectThat(dict_node['system_id'], Equals(node.system_id))
@@ -148,13 +144,16 @@
self.expectThat(
dict_node['zone_url'],
Equals(reverse('zone-view', args=[node.zone.name])))
- self.expectThat(dict_node['mac'], Equals(node.primary_mac))
- self.expectThat(dict_node['vendor'], Equals(node.primary_mac_vendor))
- self.expectThat(dict_node['macs'], Equals(node.extra_macs))
+ self.expectThat(
+ dict_node['mac'],
+ Equals(node.get_pxe_mac().mac_address.get_raw()))
+ self.expectThat(dict_node['vendor'], Equals(node.get_pxe_mac_vendor()))
+ self.assertItemsEqual(
+ dict_node['macs'],
+ [mac.mac_address.get_raw() for mac in node.get_extra_macs()])
def test_node_to_dict_include_events(self):
node = factory.make_Node()
- node = configure_mac(node)
etype = factory.make_EventType(level=logging.INFO)
events = [factory.make_Event(node, etype) for _ in range(4)]
dict_node = node_to_dict(node, event_log_count=2)
@@ -547,7 +546,6 @@
def test_node_list_ajax_returns_node_info(self):
self.client_log_in()
nodes = [factory.make_Node() for _ in range(3)]
- nodes = configure_macs(nodes)
ids = [node.system_id for node in nodes]
response = self.get_node_list_ajax(ids=ids)
json_obj = json.loads(response.content)
@@ -727,11 +725,18 @@
[listing] = get_one(interfaces_section.cssselect('span'))
self.assertEqual(mac.mac_address, listing.text_content().strip())
- def test_view_node_lists_macs_as_list_items(self):
+ def test_view_node_lists_macs_as_sorted_list_items(self):
+ # The PXE mac is listed first on the node view page.
self.client_log_in()
node = factory.make_Node()
- factory.make_MACAddress('11:11:11:11:11:11', node=node)
- factory.make_MACAddress('22:22:22:22:22:22', node=node)
+
+ macs = [
+ factory.make_MACAddress(node=node)
+ for _ in range(4)
+ ]
+ pxe_mac_index = 2
+ node.pxe_mac = macs[pxe_mac_index]
+ node.save()
response = self.client.get(reverse('node-view', args=[node.system_id]))
self.assertEqual(httplib.OK, response.status_code)
@@ -740,8 +745,12 @@
'#network-interfaces')
[interfaces_list] = interfaces_section.cssselect('ul')
interfaces = interfaces_list.cssselect('li')
+ sorted_macs = (
+ [macs[pxe_mac_index]] +
+ macs[:pxe_mac_index] + macs[pxe_mac_index + 1:]
+ )
self.assertEqual(
- ['11:11:11:11:11:11', '22:22:22:22:22:22'],
+ [mac.mac_address.get_raw() for mac in sorted_macs],
[interface.text_content().strip() for interface in interfaces])
def test_view_node_links_network_interfaces_to_networks(self):
@@ -837,7 +846,7 @@
del json_obj['action_view']
self.assertEquals(
node_to_dict(
- configure_mac(node),
+ node,
event_log_count=NodeView.number_of_events_shown),
json_obj)
|