2to3 -f has_key
[sfa.git] / sfa / rspecs / versions / pgv2.py
index b57cd9b..a4f5963 100644 (file)
@@ -1,13 +1,15 @@
-from lxml import etree
+from __future__ import print_function
+
 from copy import deepcopy
-from StringIO import StringIO
-from sfa.util.xrn import urn_to_sliver_id
-from sfa.util.plxrn import hostname_to_urn, xrn_to_hostname 
-from sfa.rspecs.rspec_version import BaseVersion
-from sfa.rspecs.rspec_elements import RSpecElement, RSpecElements
+from sfa.util.xrn import Xrn
+from sfa.rspecs.version import RSpecVersion
 from sfa.rspecs.elements.versions.pgv2Link import PGv2Link
-class PGv2(BaseVersion):
+from sfa.rspecs.elements.versions.pgv2Node import PGv2Node
+from sfa.rspecs.elements.versions.pgv2SliverType import PGv2SliverType
+from sfa.rspecs.elements.versions.pgv2Lease import PGv2Lease
+from sfa.util.sfalogging import logger
+
+class PGv2(RSpecVersion):
     type = 'ProtoGENI'
     content_type = 'ad'
     version = '2'
@@ -16,64 +18,65 @@ class PGv2(BaseVersion):
     extensions = {
         'flack': "http://www.protogeni.net/resources/rspec/ext/flack/1",
         'planetlab': "http://www.planet-lab.org/resources/sfa/ext/planetlab/1",
+        'plos': "http://www.planet-lab.org/resources/sfa/ext/plos/1",
     }
-    namespaces = dict(extensions.items() + [('default', namespace)])
-    elements = []
-
-    def get_network(self):
-        network = None
-        nodes = self.xml.xpath('//default:node[@component_manager_id][1]', namespaces=self.namespaces)
-        if nodes:
-            network  = nodes[0].get('component_manager_id')
-        return network
+    namespaces = dict(list(extensions.items()) + [('default', namespace)])
 
+    # Networks
     def get_networks(self):
-        networks = self.xml.xpath('//default:node[@component_manager_id]/@component_manager_id', namespaces=self.namespaces)
-        return set(networks)
-
-    def get_node_element(self, hostname, network=None):
-        nodes = self.xml.xpath('//default:node[@component_id[contains(., "%s")]] | node[@component_id[contains(., "%s")]]' % (hostname, hostname), namespaces=self.namespaces)
-        if isinstance(nodes,list) and nodes:
-            return nodes[0]
-        else:
-            return None
-
-    def get_node_elements(self, network=None):
-        nodes = self.xml.xpath('//default:node | //node', namespaces=self.namespaces)
-        return nodes
-
-
-    def get_nodes(self, network=None):
-        xpath = '//default:node[@component_name]/@component_id | //node[@component_name]/@component_id'
-        nodes = self.xml.xpath(xpath, namespaces=self.namespaces)
-        nodes = [xrn_to_hostname(node) for node in nodes]
-        return nodes
-
-    def get_nodes_with_slivers(self, network=None):
-        if network:
-            nodes = self.xml.xpath('//default:node[@component_manager_id="%s"][sliver_type]/@component_id' % network, namespaces=self.namespaces)
-        else:
-            nodes = self.xml.xpath('//default:node[default:sliver_type]/@component_id', namespaces=self.namespaces)
-        nodes = [xrn_to_hostname(node) for node in nodes]
-        return nodes
-
-    def get_nodes_without_slivers(self, network=None):
-        return []
+        network_names = set()
+        nodes = self.xml.xpath('//default:node[@component_manager_id] | //node[@component_manager_id]',
+                               namespaces=self.namespaces)
+        for node in nodes:
+            if 'component_manager_id' in node.attrib:
+                network_urn = node.get('component_manager_id')
+                if network_urn.startswith("urn:"):
+                    network_hrn = Xrn(network_urn).get_hrn()
+                else:
+                    # some component_manager_ids are hrns instead of urns??
+                    network_hrn = network_urn
+                network_names.add(network_hrn)
+        network_names = list(network_names)
+        networks = [{"name": x} for x in network_names]
+        return networks
+
+    # Nodes
+
+    def get_nodes(self, filter=None):
+        return PGv2Node.get_nodes(self.xml, filter)
 
-    def get_sliver_attributes(self, hostname, network=None):
-        node = self.get_node_element(hostname, network)
-        sliver = node.xpath('./default:sliver_type', namespaces=self.namespaces)
-        if sliver is not None and isinstance(sliver, list):
-            sliver = sliver[0]
-        return self.attributes_list(sliver)
+    def get_nodes_with_slivers(self):
+        return PGv2Node.get_nodes_with_slivers(self.xml)
+
+    def add_nodes(self, nodes, check_for_dupes=False, rspec_content_type=None):
+        return PGv2Node.add_nodes(self.xml, nodes, rspec_content_type)
+    
+    def merge_node(self, source_node_tag):
+        # this is untested
+        self.xml.root.append(deepcopy(source_node_tag))
+
+    # Slivers
+    
+    def get_sliver_attributes(self, component_id, network=None):
+        nodes = self.get_nodes({'component_id': '*%s*' %component_id})
+        try:
+            node = nodes[0]
+            sliver = node.xpath('./default:sliver_type', namespaces=self.namespaces)
+            if sliver is not None and isinstance(sliver, list) and len(sliver) > 0:
+                sliver = sliver[0]
+                return self.attributes_list(sliver)
+            else:
+                return []
+        except:
+            return []
 
     def get_slice_attributes(self, network=None):
         slice_attributes = []
-        nodes_with_slivers = self.get_nodes_with_slivers(network)
+        nodes_with_slivers = self.get_nodes_with_slivers()
         # TODO: default sliver attributes in the PG rspec?
         default_ns_prefix = self.namespaces['default']
         for node in nodes_with_slivers:
-            sliver_attributes = self.get_sliver_attributes(node, network)
+            sliver_attributes = self.get_sliver_attributes(node['component_id'], network)
             for sliver_attribute in sliver_attributes:
                 name=str(sliver_attribute[0])
                 text =str(sliver_attribute[1])
@@ -92,18 +95,6 @@ class PGv2(BaseVersion):
 
         return slice_attributes
 
-    def get_links(self, network=None):
-        return PGv2Link.get_links(self.xml)
-
-    def get_link_requests(self):
-        return PGv2Link.get_link_requests(self.xml)  
-
-    def add_links(self, links):
-        PGv2Link.add_links(self.xml.root, links)
-
-    def add_link_requests(self, link_tuples, append=False):
-        PGv2Link.add_link_requests(self.xml.root, link_tuples, append)
-
     def attributes_list(self, elem):
         opts = []
         if elem is not None:
@@ -117,128 +108,127 @@ class PGv2(BaseVersion):
     def add_default_sliver_attribute(self, name, value, network=None):
         pass
 
-    def add_nodes(self, nodes, check_for_dupes=False):
-        if not isinstance(nodes, list):
-            nodes = [nodes]
-        for node in nodes:
-            urn = ""
-            if check_for_dupes and \
-              self.xml.xpath('//default:node[@component_uuid="%s"]' % urn, namespaces=self.namespaces):
-                # node already exists
+    def add_slivers(self, hostnames, attributes=None, sliver_urn=None, append=False):
+        if attributes is None: attributes=[]
+        # all nodes hould already be present in the rspec. Remove all
+        # nodes that done have slivers
+        for hostname in hostnames:
+            node_elems = self.get_nodes({'component_id': '*%s*' % hostname})
+            if not node_elems:
                 continue
+            node_elem = node_elems[0]
+            
+            # determine sliver types for this node
+            valid_sliver_types = ['emulab-openvz', 'raw-pc', 'plab-vserver', 'plab-vnode']
+            requested_sliver_type = None
+            for sliver_type in node_elem.get('slivers', []):
+                if sliver_type.get('type') in valid_sliver_types:
+                    requested_sliver_type = sliver_type['type']
+            
+            if not requested_sliver_type:
+                continue
+            sliver = {'type': requested_sliver_type,
+                     'pl_tags': attributes}
+
+            # remove available element
+            for available_elem in node_elem.xpath('./default:available | ./available'):
+                node_elem.remove(available_elem)
+            
+            # remove interface elements
+            for interface_elem in node_elem.xpath('./default:interface | ./interface'):
+                node_elem.remove(interface_elem)
+        
+            # remove existing sliver_type elements
+            for sliver_type in node_elem.get('slivers', []):
+                node_elem.element.remove(sliver_type.element)
+
+            # set the client id
+            node_elem.element.set('client_id', hostname)
+            if sliver_urn:
+                pass
+                # TODO
+                # set the sliver id
+                #slice_id = sliver_info.get('slice_id', -1)
+                #node_id = sliver_info.get('node_id', -1)
+                #sliver_id = Xrn(xrn=sliver_urn, type='slice', id=str(node_id)).get_urn()
+                #node_elem.set('sliver_id', sliver_id)
+
+            # add the sliver type elemnt    
+            PGv2SliverType.add_slivers(node_elem.element, sliver)         
+
+        # remove all nodes without slivers
+        if not append:
+            for node_elem in self.get_nodes():
+                if not node_elem['client_id']:
+                    parent = node_elem.element.getparent()
+                    parent.remove(node_elem.element)
 
-            node_tag = etree.SubElement(self.xml.root, 'node', exclusive='false')
-            if 'network_urn' in node:
-                node_tag.set('component_manager_id', node['network_urn'])
-            if 'urn' in node:
-                node_tag.set('component_id', node['urn'])
-            if 'hostname' in node:
-                node_tag.set('component_name', node['hostname'])
-            # TODO: should replace plab-pc with pc model
-            node_type_tag = etree.SubElement(node_tag, 'hardware_type', name='plab-pc')
-            node_type_tag = etree.SubElement(node_tag, 'hardware_type', name='pc')
-            available_tag = etree.SubElement(node_tag, 'available', now='true')
-            sliver_type_tag = etree.SubElement(node_tag, 'sliver_type', name='plab-vserver')
-
-            pl_initscripts = node.get('pl_initscripts', {})
-            for pl_initscript in pl_initscripts.values():
-                etree.SubElement(sliver_type_tag, '{%s}initscript' % self.namespaces['planetlab'], name=pl_initscript['name'])
-
-            # protogeni uses the <sliver_type> tag to identify the types of
-            # vms available at the node.
-            # only add location tag if longitude and latitude are not null
-            if 'site' in node:
-                longitude = node['site'].get('longitude', None)
-                latitude = node['site'].get('latitude', None)
-                if longitude and latitude:
-                    location_tag = etree.SubElement(node_tag, 'location', country="us", \
-                                                    longitude=str(longitude), latitude=str(latitude))
+    def remove_slivers(self, slivers, network=None, no_dupes=False):
+        PGv2Node.remove_slivers(self.xml, slivers) 
 
-    def merge_node(self, source_node_tag):
-        # this is untested
-        self.xml.root.append(deepcopy(source_node_tag))
+    # Links
 
-    def add_slivers(self, slivers, sliver_urn=None, no_dupes=False, append=False):
+    def get_links(self, network=None):
+        return PGv2Link.get_links(self.xml)
 
-        # all nodes hould already be present in the rspec. Remove all
-        # nodes that done have slivers
-        slivers_dict = {}
-        for sliver in slivers:
-            if isinstance(sliver, basestring):
-                slivers_dict[sliver] = {'hostname': sliver}
-            elif isinstance(sliver, dict):
-                slivers_dict[sliver['hostname']] = sliver        
-
-        nodes = self.get_node_elements()
-        for node in nodes:
-            urn = node.get('component_id')
-            hostname = xrn_to_hostname(urn)
-            if hostname not in slivers_dict and not append:
-                parent = node.getparent()
-                parent.remove(node)
-            else:
-                sliver_info = slivers_dict[hostname]
-                sliver_type_elements = node.xpath('./default:sliver_type', namespaces=self.namespaces)
-                available_sliver_types = [element.attrib['name'] for element in sliver_type_elements]
-                valid_sliver_types = ['emulab-openvz', 'raw-pc', 'plab-vserver', 'plab-vnode']
-                requested_sliver_type = None
-                for valid_sliver_type in valid_sliver_types:
-                    if valid_sliver_type in available_sliver_types:
-                        requested_sliver_type = valid_sliver_type
-                if requested_sliver_type:
-                    # remove existing sliver_type tags,it needs to be recreated
-                    sliver_elem = node.xpath('./default:sliver_type | ./sliver_type', namespaces=self.namespaces)
-                    if sliver_elem and isinstance(sliver_elem, list):
-                        sliver_elem = sliver_elem[0]
-                        node.remove(sliver_elem)
-                    # set the client id
-                    node.set('client_id', hostname)
-                    if sliver_urn:
-                        # set the sliver id
-                        slice_id = sliver_info.get('slice_id', -1)
-                        node_id = sliver_info.get('node_id', -1)
-                        sliver_id = urn_to_sliver_id(sliver_urn, slice_id, node_id)
-                        node.set('sliver_id', sliver_id)
-
-                    # add the sliver element
-                    sliver_elem = etree.SubElement(node, 'sliver_type', name=requested_sliver_type)
-                    for tag in sliver_info.get('tags', []):
-                        if tag['tagname'] == 'flack_info':
-                            e = etree.SubElement(sliver_elem, '{%s}info' % self.namespaces['flack'], attrib=eval(tag['value']))
-                        elif tag['tagname'] == 'initscript':
-                            e = etree.SubElement(sliver_elem, '{%s}initscript' % self.namespaces['planetlab'], attrib={'name': tag['value']})                
-                else:
-                    # node isn't usable. just remove it from the request     
-                    parent = node.getparent()
-                    parent.remove(node)
+    def get_link_requests(self):
+        return PGv2Link.get_link_requests(self.xml)  
 
-    
+    def add_links(self, links):
+        PGv2Link.add_links(self.xml.root, links)
 
-    def remove_slivers(self, slivers, network=None, no_dupes=False):
-        for sliver in slivers:
-            node_elem = self.get_node_element(sliver['hostname'])
-            sliver_elem = node_elem.xpath('./default:sliver_type', self.namespaces)
-            if sliver_elem != None and sliver_elem != []:
-                node_elem.remove(sliver_elem[0])
+    def add_link_requests(self, link_tuples, append=False):
+        PGv2Link.add_link_requests(self.xml.root, link_tuples, append)
 
-    def add_default_sliver_attribute(self, name, value, network=None):
-        pass
+    # Leases
+
+    def get_leases(self, filter=None):
+        return PGv2Lease.get_leases(self.xml, filter)
+
+    def add_leases(self, leases, network = None, no_dupes=False):
+        PGv2Lease.add_leases(self.xml, leases)
 
-    def add_interfaces(self, interfaces, no_dupes=False):
+    # Spectrum
+
+    def get_channels(self, filter=None):
+        return []
+
+    def add_channels(self, channels, network = None, no_dupes=False):
         pass
 
+    # Utility
+
     def merge(self, in_rspec):
         """
         Merge contents for specified rspec with current rspec
         """
         from sfa.rspecs.rspec import RSpec
         # just copy over all the child elements under the root element
-        if isinstance(in_rspec, RSpec):
-            in_rspec = in_rspec.toxml()
-        tree = etree.parse(StringIO(in_rspec))
-        root = tree.getroot()
-        for child in root.getchildren():
-            self.xml.root.append(child)
+        if isinstance(in_rspec, basestring):
+            in_rspec = RSpec(in_rspec)
+
+        nodes = in_rspec.version.get_nodes()
+        # protogeni rspecs need to advertise the availabel sliver types
+        main_nodes = []
+        for node in nodes:
+            if not node['component_name']:
+                # this node element is part of a lease
+                continue
+            if 'sliver' not in node or not node['sliver']:
+                node['sliver'] = {'name': 'plab-vserver'}
+                main_nodes.append(node)
+        self.add_nodes(main_nodes)
+        self.add_links(in_rspec.version.get_links())
+        
+        # Leases
+        leases = in_rspec.version.get_leases()
+        self.add_leases(leases)
+        #
+        #rspec = RSpec(in_rspec)
+        #for child in rspec.xml.iterchildren():
+        #    self.xml.root.append(child)
+        
+        
 
     def cleanup(self):
         # remove unncecessary elements, attributes
@@ -250,19 +240,19 @@ class PGv2Ad(PGv2):
     enabled = True
     content_type = 'ad'
     schema = 'http://www.protogeni.net/resources/rspec/2/ad.xsd'
-    template = '<rspec type="advertisement" xmlns="http://www.protogeni.net/resources/rspec/2" xmlns:flack="http://www.protogeni.net/resources/rspec/ext/flack/1" xmlns:planetlab="http://www.planet-lab.org/resources/sfa/ext/planetlab/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/ad.xsd http://www.planet-lab.org/resources/sfa/ext/planetlab/1 http://www.planet-lab.org/resources/sfa/ext/planetlab/1/planetlab.xsd"/>'
+    template = '<rspec type="advertisement" xmlns="http://www.protogeni.net/resources/rspec/2" xmlns:flack="http://www.protogeni.net/resources/rspec/ext/flack/1" xmlns:plos="http://www.planet-lab.org/resources/sfa/ext/plos/1" xmlns:planetlab="http://www.planet-lab.org/resources/sfa/ext/planetlab/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/ad.xsd http://www.planet-lab.org/resources/sfa/ext/planetlab/1 http://www.planet-lab.org/resources/sfa/ext/planetlab/1/planetlab.xsd http://www.planet-lab.org/resources/sfa/ext/plos/1 http://www.planet-lab.org/resources/sfa/ext/plos/1/plos.xsd"/>'
 
 class PGv2Request(PGv2):
     enabled = True
     content_type = 'request'
     schema = 'http://www.protogeni.net/resources/rspec/2/request.xsd'
-    template = '<rspec type="request" xmlns="http://www.protogeni.net/resources/rspec/2" xmlns:flack="http://www.protogeni.net/resources/rspec/ext/flack/1" xmlns:planetlab="http://www.planet-lab.org/resources/sfa/ext/planetlab/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/request.xsd http://www.planet-lab.org/resources/sfa/ext/planetlab/1 http://www.planet-lab.org/resources/sfa/ext/planetlab/1/planetlab.xsd"/>'
+    template = '<rspec type="request" xmlns="http://www.protogeni.net/resources/rspec/2" xmlns:flack="http://www.protogeni.net/resources/rspec/ext/flack/1" xmlns:plos="http://www.planet-lab.org/resources/sfa/ext/plos/1" xmlns:planetlab="http://www.planet-lab.org/resources/sfa/ext/planetlab/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/request.xsd http://www.planet-lab.org/resources/sfa/ext/planetlab/1 http://www.planet-lab.org/resources/sfa/ext/planetlab/1/planetlab.xsd http://www.planet-lab.org/resources/sfa/ext/plos/1 http://www.planet-lab.org/resources/sfa/ext/plos/1/plos.xsd"/>'
 
 class PGv2Manifest(PGv2):
     enabled = True
     content_type = 'manifest'
     schema = 'http://www.protogeni.net/resources/rspec/2/manifest.xsd'
-    template = '<rspec type="manifest" xmlns="http://www.protogeni.net/resources/rspec/2" xmlns:flack="http://www.protogeni.net/resources/rspec/ext/flack/1" xmlns:planetlab="http://www.planet-lab.org/resources/sfa/ext/planetlab/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/manifest.xsd http://www.planet-lab.org/resources/sfa/ext/planetlab/1 http://www.planet-lab.org/resources/sfa/ext/planetlab/1/planetlab.xsd"/>'
+    template = '<rspec type="manifest" xmlns="http://www.protogeni.net/resources/rspec/2" xmlns:plos="http://www.planet-lab.org/resources/sfa/ext/plos/1" xmlns:flack="http://www.protogeni.net/resources/rspec/ext/flack/1" xmlns:planetlab="http://www.planet-lab.org/resources/sfa/ext/planetlab/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/manifest.xsd http://www.planet-lab.org/resources/sfa/ext/planetlab/1 http://www.planet-lab.org/resources/sfa/ext/planetlab/1/planetlab.xsd http://www.planet-lab.org/resources/sfa/ext/plos/1 http://www.planet-lab.org/resources/sfa/ext/plos/1/plos.xsd"/>'
 
      
 
@@ -273,4 +263,4 @@ if __name__ == '__main__':
     r = RSpec('/tmp/pg.rspec')
     r.load_rspec_elements(PGv2.elements)
     r.namespaces = PGv2.namespaces
-    print r.get(RSpecElements.NODE)
+    print(r.get(RSpecElements.NODE))