include opstates in ad rspec. include ssh-user in manifest rspec
authorTony Mack <tmack@paris.CS.Princeton.EDU>
Mon, 21 Jan 2013 04:40:20 +0000 (23:40 -0500)
committerTony Mack <tmack@paris.CS.Princeton.EDU>
Mon, 21 Jan 2013 04:40:20 +0000 (23:40 -0500)
sfa/planetlab/plaggregate.py
sfa/rspecs/elements/login.py
sfa/rspecs/elements/services.py
sfa/rspecs/elements/v3/__init__.py [new file with mode: 0644]
sfa/rspecs/elements/v3/node.py [new file with mode: 0644]
sfa/rspecs/elements/v3/services.py [new file with mode: 0644]
sfa/rspecs/versions/pgv3.py

index 6ad1e47..1095f8d 100644 (file)
@@ -136,10 +136,42 @@ class PlAggregate:
             filter['name'] = list(names)
         if slice_ids:
             filter['slice_id'] = list(slice_ids)
+        # get slices
         slices = self.driver.shell.GetSlices(filter)
         if not slices:
             return []
-        slice = slices[0]
+        slice = slices[0]        
+
+        # get sliver users
+        persons = []
+        person_ids = []
+        for slice in slices:
+            person_ids.extend(slice['person_ids'])
+        if person_ids:
+            persons = self.driver.shell.GetPersons(person_ids)
+                 
+        # get user keys
+        keys = {}
+        key_ids = []
+        for person in persons:
+            key_ids.extend(person['key_ids'])
+        
+        if key_ids:
+            key_list = self.driver.shell.GetKeys(key_ids)
+            for key in key_list:
+                keys[key['key_id']] = key  
+
+        # construct user key info
+        users = []
+        for person in persons:
+            name = person['email'][0:person['email'].index('@')]
+            user = {
+                'login': slice['name'], 
+                'user_urn': Xrn('%s.%s' % (self.driver.hrn, name), type='user').urn,
+                'keys': [keys[k_id]['key'] for k_id in person['key_ids'] if k_id in keys]
+            }
+            users.append(user)
+
         if node_ids:
             node_ids = [node_id for node_id in node_ids if node_id in slice['node_ids']]
             slice['node_ids'] = node_ids
@@ -152,6 +184,7 @@ class PlAggregate:
             sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
             node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
             node['urn'] = node['sliver_id'] 
+            node['services_user'] = users
             slivers.append(node)
         return slivers
 
@@ -220,8 +253,14 @@ class PlAggregate:
         rspec_node['slivers'] = [rspec_sliver]
 
         # slivers always provide the ssh service
-        login = Login({'authentication': 'ssh-keys', 'hostname': sliver['hostname'], 'port':'22', 'username': sliver['name']})
-        service = Services({'login': login})
+        login = Login({'authentication': 'ssh-keys', 
+                       'hostname': sliver['hostname'], 
+                       'port':'22', 
+                       'username': sliver['name'],
+                       'login': sliver['name']
+                      })
+        service = Services({'login': login,
+                            'services_user': sliver['services_user']})
         rspec_node['services'] = [service]    
         return rspec_node      
 
index 99dc5c3..51741a9 100644 (file)
@@ -5,5 +5,5 @@ class Login(Element):
         'authentication',
         'hostname',
         'port',
-        'username'
+        'username',
     ]
index df0546d..e90b645 100644 (file)
@@ -6,5 +6,6 @@ class Services(Element):
         'install',
         'execute',
         'login',
+        'services_user',
     ]
 
diff --git a/sfa/rspecs/elements/v3/__init__.py b/sfa/rspecs/elements/v3/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/sfa/rspecs/elements/v3/node.py b/sfa/rspecs/elements/v3/node.py
new file mode 100644 (file)
index 0000000..f8c0d01
--- /dev/null
@@ -0,0 +1,145 @@
+from sfa.util.xrn import Xrn
+from sfa.util.xml import XpathFilter
+
+from sfa.rspecs.elements.node import Node
+from sfa.rspecs.elements.sliver import Sliver
+from sfa.rspecs.elements.location import Location
+from sfa.rspecs.elements.hardware_type import HardwareType
+from sfa.rspecs.elements.disk_image import DiskImage
+from sfa.rspecs.elements.interface import Interface
+from sfa.rspecs.elements.bwlimit import BWlimit
+from sfa.rspecs.elements.pltag import PLTag
+from sfa.rspecs.elements.v3.services import Services     
+from sfa.rspecs.elements.versions.pgv2SliverType import PGv2SliverType     
+from sfa.rspecs.elements.versions.pgv2Interface import PGv2Interface     
+
+from sfa.planetlab.plxrn import xrn_to_hostname
+
+class Node:
+    @staticmethod
+    def add_nodes(xml, nodes):
+        node_elems = []
+        for node in nodes:
+            node_fields = ['component_manager_id', 'component_id', 'client_id', 'sliver_id', 'exclusive']
+            node_elem = xml.add_instance('node', node, node_fields)
+            node_elems.append(node_elem)
+            # set component name
+            if node.get('component_id'):
+                component_name = xrn_to_hostname(node['component_id'])
+                node_elem.set('component_name', component_name)
+            # set hardware types
+            if node.get('hardware_types'):
+                for hardware_type in node.get('hardware_types', []): 
+                    node_elem.add_instance('hardware_type', hardware_type, HardwareType.fields)
+            # set location
+            if node.get('location'):
+                node_elem.add_instance('location', node['location'], Location.fields)       
+            # set interfaces
+            PGv2Interface.add_interfaces(node_elem, node.get('interfaces'))
+            #if node.get('interfaces'):
+            #    for interface in  node.get('interfaces', []):
+            #        node_elem.add_instance('interface', interface, ['component_id', 'client_id'])
+            # set available element
+            if node.get('available'):
+                available_elem = node_elem.add_element('available', now=node['available'])
+            # add services
+            Services.add_services(node_elem, node.get('services', [])) 
+            # add slivers
+            slivers = node.get('slivers', [])
+            if not slivers:
+                # we must still advertise the available sliver types
+                slivers = Sliver({'type': 'plab-vserver'})
+                # we must also advertise the available initscripts
+                slivers['tags'] = []
+                if node.get('pl_initscripts'): 
+                    for initscript in node.get('pl_initscripts', []):
+                        slivers['tags'].append({'name': 'initscript', 'value': initscript['name']})
+            PGv2SliverType.add_slivers(node_elem, slivers)
+        
+        return node_elems
+
+    @staticmethod
+    def get_nodes(xml, filter={}):
+        xpath = '//node%s | //default:node%s' % (XpathFilter.xpath(filter), XpathFilter.xpath(filter))
+        node_elems = xml.xpath(xpath)
+        return Node.get_node_objs(node_elems)
+
+    @staticmethod
+    def get_nodes_with_slivers(xml, filter={}):
+        xpath = '//node[count(sliver_type)>0] | //default:node[count(default:sliver_type) > 0]' 
+        node_elems = xml.xpath(xpath)        
+        return Node.get_node_objs(node_elems)
+
+    @staticmethod
+    def get_node_objs(node_elems):
+        nodes = []
+        for node_elem in node_elems:
+            node = Node(node_elem.attrib, node_elem)
+            nodes.append(node) 
+            if 'component_id' in node_elem.attrib:
+                node['authority_id'] = Xrn(node_elem.attrib['component_id']).get_authority_urn()
+            
+            # get hardware types
+            hardware_type_elems = node_elem.xpath('./default:hardware_type | ./hardware_type')
+            node['hardware_types'] = [hw_type.get_instance(HardwareType) for hw_type in hardware_type_elems]
+            
+            # get location
+            location_elems = node_elem.xpath('./default:location | ./location')
+            locations = [location_elem.get_instance(Location) for location_elem in location_elems]
+            if len(locations) > 0:
+                node['location'] = locations[0]
+
+            # get interfaces
+            iface_elems = node_elem.xpath('./default:interface | ./interface')
+            node['interfaces'] = [iface_elem.get_instance(Interface) for iface_elem in iface_elems]
+
+            # get services
+            node['services'] = Services.get_services(node_elem)
+            
+            # get slivers
+            node['slivers'] = PGv2SliverType.get_slivers(node_elem)    
+            available_elems = node_elem.xpath('./default:available | ./available')
+            if len(available_elems) > 0 and 'name' in available_elems[0].attrib:
+                if available_elems[0].attrib.get('now', '').lower() == 'true': 
+                    node['boot_state'] = 'boot'
+                else: 
+                    node['boot_state'] = 'disabled' 
+        return nodes
+
+
+    @staticmethod
+    def add_slivers(xml, slivers):
+        component_ids = []
+        for sliver in slivers:
+            filter = {}
+            if isinstance(sliver, str):
+                filter['component_id'] = '*%s*' % sliver
+                sliver = {}
+            elif 'component_id' in sliver and sliver['component_id']:
+                filter['component_id'] = '*%s*' % sliver['component_id']
+            if not filter: 
+                continue
+            nodes = Node.get_nodes(xml, filter)
+            if not nodes:
+                continue
+            node = nodes[0]
+            PGv2SliverType.add_slivers(node, sliver)
+
+    @staticmethod
+    def remove_slivers(xml, hostnames):
+        for hostname in hostnames:
+            nodes = Node.get_nodes(xml, {'component_id': '*%s*' % hostname})
+            for node in nodes:
+                slivers = PGv2SliverType.get_slivers(node.element)
+                for sliver in slivers:
+                    node.element.remove(sliver.element) 
+if __name__ == '__main__':
+    from sfa.rspecs.rspec import RSpec
+    import pdb
+    r = RSpec('/tmp/emulab.rspec')
+    r2 = RSpec(version = 'GENI')
+    nodes = Node.get_nodes(r.xml)
+    Node.add_nodes(r2.xml.root, nodes)
+    #pdb.set_trace()
+        
+                                    
diff --git a/sfa/rspecs/elements/v3/services.py b/sfa/rspecs/elements/v3/services.py
new file mode 100644 (file)
index 0000000..b4ac1ca
--- /dev/null
@@ -0,0 +1,60 @@
+from sfa.rspecs.elements.element import Element  
+from sfa.rspecs.elements.execute import Execute  
+from sfa.rspecs.elements.install import Install  
+from sfa.rspecs.elements.services import Services  
+from sfa.rspecs.elements.login import Login
+
+class Services:
+    @staticmethod
+    def add_services(xml, services):
+        if not services:
+            return 
+        for service in services:
+            service_elem = xml.add_element('services')
+            child_elements = {'install': Install.fields,
+                              'execute': Execute.fields,
+                              'login': Login.fields}
+            for (name, fields) in child_elements.items():
+                child = service.get(name)
+                if not child: 
+                    continue
+                if isinstance(child, dict):
+                    service_elem.add_instance(name, child, fields)
+                elif isinstance(child, list):
+                    for obj in child:
+                        service_elem.add_instance(name, obj, fields)
+
+            # add ssh_users
+            if service['services_user']:
+                for ssh_user in service['services_user']: 
+                    ssh_user_elem = service_elem.add_element('{%s}services_user' % xml.namespaces['ssh-user'],
+                                                             login=ssh_user['login'],
+                                                             user_urn=ssh_user['user_urn'])
+                    for key in ssh_user['keys']:
+                        pkey_elem = ssh_user_elem.add_element('{%s}public_key' % xml.namespaces['ssh-user'])
+                        pkey_elem.element.text=key
+                          
+              
+    @staticmethod
+    def get_services(xml):
+        services = []
+        for services_elem in xml.xpath('./default:services | ./services'):
+            service = Services(services_elem.attrib, services_elem)
+            # get install 
+            install_elems = xml.xpath('./default:install | ./install')
+            service['install'] = [install_elem.get_instance(Install) for install_elem in install_elems]
+            # get execute
+            execute_elems = xml.xpath('./default:execute | ./execute')
+            service['execute'] = [execute_elem.get_instance(Execute) for execute_elem in execute_elems]
+            # get login
+            login_elems = xml.xpath('./default:login | ./login')
+            service['login'] = [login_elem.get_instance(Login) for login_elem in login_elems]
+            
+            ssh_user_elems = xml.xpath('./ssh-user:service_user | ./service_user')
+            service_users = []    
+            for ssh_user_elem in ssh_user_elems:
+                service_user = ssh_user_elem.get_instance(None, fields=['login', 'user_urn'])
+            service['services_user'] = service_user
+            services.append(service)  
+        return services
+
index 47f0dae..43b744c 100644 (file)
@@ -1,4 +1,5 @@
 from sfa.rspecs.versions.pgv2 import PGv2
+from sfa.rspecs.elements.v3.node import Node 
 
 class GENIv3(PGv2):
     type = 'GENI'
@@ -19,7 +20,34 @@ class GENIv3Ad(GENIv3):
     enabled = True
     content_type = 'ad'
     schema = 'http://www.geni.net/resources/rspec/3/ad.xsd'
-    template = '<rspec type="advertisement" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.geni.net/resources/rspec/3" 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" xsi:schemaLocation="http://www.geni.net/resources/rspec/3 http://www.geni.net/resources/rspec/3/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 http://www.geni.net/resources/rspec/ext/opstate/1 http://www.protogeni.net/resources/rspec/ext/opstate/1/ad.xsd"/>'
+    template = """<rspec type="advertisement" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.geni.net/resources/rspec/3" 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:opstate="http://www.geni.net/resources/rspec/ext/opstate/1" xsi:schemaLocation="http://www.geni.net/resources/rspec/3 http://www.geni.net/resources/rspec/3/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 http://www.geni.net/resources/rspec/ext/opstate/1 http://www.protogeni.net/resources/rspec/ext/opstate/1/ad.xsd">
+    <opstate:rspec_opstate aggregate_manager_id="urn:publicid:IDN+plc+authority+cm" start="geni_notready">
+      <opstate:sliver_type name="plab-vserver" />
+      <opstate:sliver_type name="plos-pc" />
+      <opstate:state name="geni_notready">
+        <opstate:action name="geni_start" next="geni_configuring">
+          <opstate:description>Boot the node</opstate:description>
+        </opstate:action>
+        <opstate:description>VMs begin powered down or inactive. They
+        must be explicitly booted before use.</opstate:description>
+      </opstate:state>
+      <opstate:state name="geni_configuring">
+        <opstate:wait type="geni_success" next="geni_ready" />
+        <opstate:wait type="geni_failure" next="geni_failed" />
+        <opstate:description>Booting takes a significant amount of time, so it
+        happens asynchronously while the node is in this
+        state.</opstate:description>
+      </opstate:state>
+      <opstate:state name="geni_ready">
+        <opstate:description>The node is up and ready to use.</opstate:description>
+      </opstate:state>
+      <opstate:state name="geni_failed">
+        <opstate:description>The node has failed and requires administrator
+        intervention before it can be used. Please contact support
+        for assistance.</opstate:description>
+      </opstate:state>
+    </opstate:rspec_opstate>
+</rspec>"""
 
 class GENIv3Request(GENIv3):
     enabled = True
@@ -31,5 +59,11 @@ class GENIv2Manifest(GENIv3):
     enabled = True
     content_type = 'manifest'
     schema = 'http://www.geni.net/resources/rspec/3/manifest.xsd'
-    template = '<rspec type="manifest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.geni.net/resources/rspec/3" 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" xsi:schemaLocation="http://www.geni.net/resources/rspec/3 http://www.geni.net/resources/rspec/3/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"/>'
-     
+    template = '<rspec type="manifest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.geni.net/resources/rspec/3" 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:ssh-user="http://www.geni.net/resources/rspec/ext/user/1" xsi:schemaLocation="http://www.geni.net/resources/rspec/3 http://www.geni.net/resources/rspec/3/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 http://www.geni.net/resources/rspec/ext/user/1 http://www.geni.net/resources/rspec/ext/user/1/manifest.xsd"/>'
+
+
+    def add_nodes(self, nodes, check_for_dupes=False):
+        return Node.add_nodes(self.xml, nodes)
+    
+    def get_nodes(self, filter=None):
+        return Node.get_nodes(self.xml, filter)