From 317654cef00033e3639e599698a2bab0b6e7f82b Mon Sep 17 00:00:00 2001
From: Leigh B Stoller <stoller@flux.utah.edu>
Date: Wed, 11 Oct 2017 07:55:29 -0600
Subject: [PATCH] Support for node attributes.

---
 apt/APT_Rspec.pm.in  | 11 ++++++++++-
 apt/nsgenilib.py.in  | 30 +++++++++++++++++++++++++-----
 apt/rspec2genilib.in |  8 ++++++++
 3 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/apt/APT_Rspec.pm.in b/apt/APT_Rspec.pm.in
index b30c79a79f..5430cb891f 100644
--- a/apt/APT_Rspec.pm.in
+++ b/apt/APT_Rspec.pm.in
@@ -835,6 +835,7 @@ sub new($$$$$)
 	"services"		=> [],
 	"statements"		=> [],
 	"desires"		=> {},
+	"attributes"		=> {},
 	"ifaces"		=> {},
 	"ifacelist"             => [],
 	"blockstores"		=> {},
@@ -858,6 +859,8 @@ sub blockstores($)		{ return $_[0]->{'blockstores'}; }
 sub ifaces($)			{ return $_[0]->{'ifaces'}; }
 sub ifacelist($)		{ return $_[0]->{'ifacelist'}; }
 sub services($)			{ return $_[0]->{'services'}; }
+sub desires($)			{ return $_[0]->{'services'}; }
+sub attributes($)		{ return $_[0]->{'attributes'}; }
 sub pipes($)			{ return $_[0]->{'pipes'}; }
 sub firewall_style($)		{ return $_[0]->{'firewall_style'}; }
 sub firewall_rules($)		{ return $_[0]->{'firewall_rules'}; }
@@ -1220,6 +1223,12 @@ sub addNode($$$)
 		$node->{"desires"}->{$desire} = $weight;
 		last SWITCH;
 	    };
+	    /^node_attribute$/i && do {
+		my $key   = GetTextOrFail("key", $child);
+		my $value = GetTextOrFail("value", $child);
+		$node->{"attributes"}->{$key} = $value;
+		last SWITCH;
+	    };
 	    /^moonshot_chassis$/i && do {
 		# Convert to a desire
 		my $chassis = GetTextOrFail("chassis", $child);
@@ -1295,7 +1304,7 @@ sub Compare($$)
 		# Handled up above in CompareNodes.
 		last SWITCH;
 	    };
-	    /^(xen_settings|desires|pipes|blockstores)$/i && do {
+	    /^(xen_settings|desires|pipes|blockstores|attributes)$/i && do {
 		return 1
 		    if (APT_Rspec::CompareHashes("Node: $client_id: $key",
 						 $val1, $val2));
diff --git a/apt/nsgenilib.py.in b/apt/nsgenilib.py.in
index 5384e108cb..1820b267ff 100644
--- a/apt/nsgenilib.py.in
+++ b/apt/nsgenilib.py.in
@@ -774,11 +774,31 @@ for child in tree.getroot():
         vname  = row.find("vname").text
         key    = row.find("attrkey").text
         val    = row.find("attrvalue").text
-        raw    = etree.Element("{%s}node_attribute" %
-                               (RSpec.Namespaces.EMULAB.name))
-        raw.attrib["attrkey"]   = key
-        raw.attrib["attrvalue"] = val
-        nodes[vname].addRawElement(raw)
+        node   = nodes[vname]
+
+        #
+        # Many node attributes, we have to translate some, the rest
+        # are passed through.
+        #
+        if key == "routable_control_ip":
+            if val.lower() == "true":
+                node.routable_control_ip = True
+                pass
+        elif ((key == "MEMORY_SIZE" or key == "XEN_MEMSIZE") and
+              node.type == "emulab-xen"):
+            node.ram = int(val) / 1024
+        elif ((key == "XEN_CORES" or key == "VM_CPUS") and
+              node.type == "emulab-xen"):
+            node.cores = int(val)
+        elif key == "XEN_EXTRAFS" and node.type == "emulab-xen":
+            node.disk = int(val)
+        else:
+            raw = etree.Element("{%s}node_attribute" %
+                                (RSpec.Namespaces.EMULAB.name))
+            raw.attrib["key"]   = key
+            raw.attrib["value"] = val
+            node.addRawElement(raw)
+            pass
         pass
     if child.tag == "firewall_rules":
         #
diff --git a/apt/rspec2genilib.in b/apt/rspec2genilib.in
index 1378f4648f..4085e53ca5 100644
--- a/apt/rspec2genilib.in
+++ b/apt/rspec2genilib.in
@@ -363,6 +363,14 @@ sub GenerateNodeStatements($)
 	    $node->addTagStatement("Desire('$desire','$weight')");
 	}
 	
+	#
+	# Node Attributes.
+	#
+	foreach my $key (sort(keys(%{ $node->attributes() }))) {
+	    my $value = $node->attributes()->{$key};
+	    $node->addTagStatement("Attribute('$key','$value')");
+	}
+	
 	#
 	# Interfaces.
 	#
-- 
GitLab