From: Loic Baron Date: Fri, 14 Feb 2014 16:30:32 +0000 (+0100) Subject: Ofelia OpenFlow RSpec parsing support X-Git-Tag: sfa-3.1-2~4 X-Git-Url: http://git.onelab.eu/?p=sfa.git;a=commitdiff_plain;h=9db3c20fbf81539809def807beea35a88318de7a Ofelia OpenFlow RSpec parsing support --- diff --git a/sfa/rspecs/elements/datapath.py b/sfa/rspecs/elements/datapath.py new file mode 100644 index 00000000..5b51e1bb --- /dev/null +++ b/sfa/rspecs/elements/datapath.py @@ -0,0 +1,12 @@ +from sfa.rspecs.elements.element import Element + +class Datapath(Element): + + fields = [ + 'component_id', + 'component_manager_id', + 'dp_id', + 'ports', + ] + + diff --git a/sfa/rspecs/elements/port.py b/sfa/rspecs/elements/port.py new file mode 100644 index 00000000..2817b6b3 --- /dev/null +++ b/sfa/rspecs/elements/port.py @@ -0,0 +1,7 @@ +from sfa.rspecs.elements.element import Element + +class Port(Element): + fields = [ + 'num', + 'name', + ] diff --git a/sfa/rspecs/elements/versions/ofeliav1Port.py b/sfa/rspecs/elements/versions/ofeliav1Port.py new file mode 100644 index 00000000..07520ef3 --- /dev/null +++ b/sfa/rspecs/elements/versions/ofeliav1Port.py @@ -0,0 +1,53 @@ +from sfa.util.xrn import Xrn +from sfa.util.xml import XmlElement + +from sfa.rspecs.elements.element import Element +from sfa.rspecs.elements.port import Port + +class Ofeliav1Port: + + @staticmethod + def add_portrs(xml, ports): + raise Exception, "not implemented yet" + if not ports: + return + if not isinstance(ports, list): + ports = [ports] + for port in ports: + port_elem = xml.add_instance('port', port, ['name']) + tags = port.get('tags', []) + if tags: + for tag in tags: + Ofeliav1Port.add_port_attribute(port_elem, tag['tagname'], tag['value']) + + @staticmethod + def add_port_attribute(xml, name, value): + raise Exception, "not implemented yet" + elem = xml.add_element(name) + elem.set_text(value) + + @staticmethod + def get_port_attributes(xml): + attribs = [] + for elem in xml.iterchildren(): + if elem.tag not in Port.fields: + xml_element = XmlElement(elem, xml.namespaces) + instance = Element(fields=xml_element, element=elem) + instance['name'] = elem.tag + instance['value'] = elem.text + attribs.append(instance) + return attribs + + @staticmethod + def get_ports(xml, filter={}): + xpath = './openflow:port | ./port' + port_elems = xml.xpath(xpath) + ports = [] + for port_elem in port_elems: + port = Port(port_elem.attrib,port_elem) + #if 'component_id' in xml.attrib: + # port['component_id'] = xml.attrib['component_id'] + #port['tags'] = Ofeliav1Port.get_port_attributes(port_elem) + ports.append(port) + return ports + diff --git a/sfa/rspecs/elements/versions/ofeliav1datapath.py b/sfa/rspecs/elements/versions/ofeliav1datapath.py new file mode 100644 index 00000000..86a38002 --- /dev/null +++ b/sfa/rspecs/elements/versions/ofeliav1datapath.py @@ -0,0 +1,157 @@ +from sfa.util.sfalogging import logger +from sfa.util.xml import XpathFilter +from sfa.util.xrn import Xrn, get_leaf + +from sfa.rspecs.elements.element import Element +from sfa.rspecs.elements.datapath import Datapath +from sfa.rspecs.elements.node import NodeElement +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.versions.sfav1Sliver import SFAv1Sliver +from sfa.rspecs.elements.versions.sfav1PLTag import SFAv1PLTag +from sfa.rspecs.elements.versions.pgv2Services import PGv2Services +from sfa.rspecs.elements.versions.ofeliav1Port import Ofeliav1Port + + +class Ofeliav1Datapath: + + @staticmethod + def get_datapaths(xml, filter={}): + #xpath = '//datapath%s | //default:datapath%s' % (XpathFilter.xpath(filter), XpathFilter.xpath(filter)) + xpath = '//datapath%s | //openflow:datapath%s' % (XpathFilter.xpath(filter), XpathFilter.xpath(filter)) + datapath_elems = xml.xpath(xpath) + return Ofeliav1Datapath.get_datapath_objs(datapath_elems) + + @staticmethod + def get_datapath_objs(datapath_elems): + datapaths = [] + for datapath_elem in datapath_elems: + datapath = Datapath(datapath_elem.attrib, datapath_elem) + # get ports + datapath['ports'] = Ofeliav1Port.get_ports(datapath_elem) + datapaths.append(datapath) + return datapaths + +# @staticmethod +# def add_nodes(xml, nodes, rspec_content_type=None): +# network_elems = xml.xpath('//network') +# if len(network_elems) > 0: +# network_elem = network_elems[0] +# elif len(nodes) > 0 and nodes[0].get('component_manager_id'): +# network_urn = nodes[0]['component_manager_id'] +# network_elem = xml.add_element('network', name = Xrn(network_urn).get_hrn()) +# else: +# network_elem = xml +# +# node_elems = [] +# for node in nodes: +# node_fields = ['component_manager_id', 'component_id', 'boot_state'] +# node_elem = network_elem.add_instance('node', node, node_fields) +# node_elems.append(node_elem) +# +# # determine network hrn +# network_hrn = None +# if 'component_manager_id' in node and node['component_manager_id']: +# network_hrn = Xrn(node['component_manager_id']).get_hrn() +# +# # set component_name attribute and hostname element +# if 'component_id' in node and node['component_id']: +# component_name = Xrn.unescape(get_leaf(Xrn(node['component_id']).get_hrn())) +# node_elem.set('component_name', component_name) +# hostname_elem = node_elem.add_element('hostname') +# hostname_elem.set_text(component_name) +# +# # set site id +# if 'authority_id' in node and node['authority_id']: +# node_elem.set('site_id', node['authority_id']) +# +# # add locaiton +# location = node.get('location') +# if location: +# node_elem.add_instance('location', location, Location.fields) +# +# # add exclusive tag to distinguish between Reservable and Shared nodes +# exclusive_elem = node_elem.add_element('exclusive') +# if node.get('exclusive') and node.get('exclusive') == 'true': +# exclusive_elem.set_text('TRUE') +# # add granularity of the reservation system +# granularity = node.get('granularity') +# if granularity: +# node_elem.add_instance('granularity', granularity, granularity.fields) +# else: +# exclusive_elem.set_text('FALSE') +# +# +# if isinstance(node.get('interfaces'), list): +# for interface in node.get('interfaces', []): +# node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4']) +# +# #if 'bw_unallocated' in node and node['bw_unallocated']: +# # bw_unallocated = etree.SubElement(node_elem, 'bw_unallocated', units='kbps').text = str(int(node['bw_unallocated'])/1000) +# +# PGv2Services.add_services(node_elem, node.get('services', [])) +# tags = node.get('tags', []) +# if tags: +# for tag in tags: +# # backdoor for FITeagle +# # Alexander Willner +# if tag['tagname']=="fiteagle_settings": +# tag_elem = node_elem.add_element(tag['tagname']) +# for subtag in tag['value']: +# subtag_elem = tag_elem.add_element('setting') +# subtag_elem.set('name', str(subtag['tagname'])) +# subtag_elem.set('description', str(subtag['description'])) +# subtag_elem.set_text(subtag['value']) +# else: +# tag_elem = node_elem.add_element(tag['tagname']) +# tag_elem.set_text(tag['value']) +# SFAv1Sliver.add_slivers(node_elem, node.get('slivers', [])) +# +# # add sliver tag in Request Rspec +# if rspec_content_type == "request": +# node_elem.add_instance('sliver', '', []) +# +# @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 = SFAv1Node.get_nodes(xml, filter) +# if not nodes: +# continue +# node = nodes[0] +# SFAv1Sliver.add_slivers(node, sliver) +# +# @staticmethod +# def remove_slivers(xml, hostnames): +# for hostname in hostnames: +# nodes = SFAv1Node.get_nodes(xml, {'component_id': '*%s*' % hostname}) +# for node in nodes: +# slivers = SFAv1Sliver.get_slivers(node.element) +# for sliver in slivers: +# node.element.remove(sliver.element) +# +# @staticmethod +# def get_nodes(xml, filter={}): +# xpath = '//node%s | //default:node%s' % (XpathFilter.xpath(filter), XpathFilter.xpath(filter)) +# node_elems = xml.xpath(xpath) +# return SFAv1Node.get_node_objs(node_elems) +# +# @staticmethod +# def get_nodes_with_slivers(xml): +# xpath = '//node[count(sliver)>0] | //default:node[count(default:sliver)>0]' +# node_elems = xml.xpath(xpath) +# return SFAv1Node.get_node_objs(node_elems) +# diff --git a/sfa/rspecs/elements/versions/ofeliav1link.py b/sfa/rspecs/elements/versions/ofeliav1link.py new file mode 100644 index 00000000..3fc2eb24 --- /dev/null +++ b/sfa/rspecs/elements/versions/ofeliav1link.py @@ -0,0 +1,22 @@ +from sfa.util.sfalogging import logger +from sfa.util.xml import XpathFilter +from sfa.util.xrn import Xrn, get_leaf + +from sfa.rspecs.elements.element import Element +from sfa.rspecs.elements.link import Link + +class Ofeliav1Link: + + @staticmethod + def get_links(xml, filter={}): + xpath = '//link%s | //openflow:link%s' % (XpathFilter.xpath(filter), XpathFilter.xpath(filter)) + link_elems = xml.xpath(xpath) + return Ofeliav1Link.get_link_objs(link_elems) + + @staticmethod + def get_link_objs(link_elems): + links = [] + for link_elem in link_elems: + link = Link(link_elem.attrib, link_elem) + links.append(link) + return links diff --git a/sfa/rspecs/versions/ofeliav1.py b/sfa/rspecs/versions/ofeliav1.py new file mode 100755 index 00000000..cd206ffc --- /dev/null +++ b/sfa/rspecs/versions/ofeliav1.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from copy import deepcopy +from lxml import etree + +from sfa.util.sfalogging import logger +from sfa.util.xrn import hrn_to_urn, urn_to_hrn +from sfa.rspecs.version import RSpecVersion +from sfa.rspecs.elements.element import Element +from sfa.rspecs.elements.versions.pgv2Link import PGv2Link +from sfa.rspecs.elements.versions.sfav1Node import SFAv1Node +from sfa.rspecs.elements.versions.sfav1Sliver import SFAv1Sliver +from sfa.rspecs.elements.versions.sfav1Lease import SFAv1Lease +from sfa.rspecs.elements.versions.ofeliav1datapath import Ofeliav1Datapath +from sfa.rspecs.elements.versions.ofeliav1link import Ofeliav1Link + +class Ofelia(RSpecVersion): + enabled = True + type = 'OFELIA' + content_type = '*' + version = '1' + schema = 'https://github.com/fp7-ofelia/ocf/blob/ocf.rspecs/openflow/schemas/ad.xsd' + namespace = 'openflow' + extensions = {} + namespaces = dict(extensions.items() + [('default', namespace)]) + #template = '' % type + template = '' + + # Network + def get_networks(self): + raise Exception, "Not implemented" + network_elems = self.xml.xpath('//network') + networks = [network_elem.get_instance(fields=['name', 'slice']) for \ + network_elem in network_elems] + return networks + + + def add_network(self, network): + raise Exception, "Not implemented" + network_tags = self.xml.xpath('//network[@name="%s"]' % network) + if not network_tags: + network_tag = self.xml.add_element('network', name=network) + else: + network_tag = network_tags[0] + return network_tag + +# These are all resources +# get_resources function can return all resources or a specific type of resource + def get_resources(self, filter=None, type=None): + resources = list() + if not type or type=='datapath': + datapaths = self.get_datapaths(filter) + for datapath in datapaths: + datapath['type']='datapath' + resources.extend(datapaths) + if not type or type=='link': + links = self.get_links(filter) + for link in links: + link['type']='link' + resources.extend(links) + return resources + + # Datapaths + def get_datapaths(self, filter=None): + return Ofeliav1Datapath.get_datapaths(self.xml, filter) + + # Links + def get_links(self, filter=None): + return Ofeliav1Link.get_links(self.xml, filter) + +# def get_link_requests(self): +# return PGv2Link.get_link_requests(self.xml) +# +# def add_links(self, links): +# networks = self.get_networks() +# if len(networks) > 0: +# xml = networks[0].element +# else: +# xml = self.xml +# PGv2Link.add_links(xml, links) +# +# def add_link_requests(self, links): +# PGv2Link.add_link_requests(self.xml, links) + + + + # Slivers + + def add_slivers(self, hostnames, attributes=[], sliver_urn=None, append=False): + # add slice name to network tag + network_tags = self.xml.xpath('//network') + if network_tags: + network_tag = network_tags[0] + network_tag.set('slice', urn_to_hrn(sliver_urn)[0]) + + # add slivers + sliver = {'name':sliver_urn, + 'pl_tags': attributes} + for hostname in hostnames: + if sliver_urn: + sliver['name'] = sliver_urn + node_elems = self.get_nodes({'component_id': '*%s*' % hostname}) + if not node_elems: + continue + node_elem = node_elems[0] + SFAv1Sliver.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['slivers']: + parent = node_elem.element.getparent() + parent.remove(node_elem.element) + + + def remove_slivers(self, slivers, network=None, no_dupes=False): + SFAv1Node.remove_slivers(self.xml, slivers) + + def get_slice_attributes(self, network=None): + attributes = [] + nodes_with_slivers = self.get_nodes_with_slivers() + for default_attribute in self.get_default_sliver_attributes(network): + attribute = default_attribute.copy() + attribute['node_id'] = None + attributes.append(attribute) + for node in nodes_with_slivers: + nodename=node['component_name'] + sliver_attributes = self.get_sliver_attributes(nodename, network) + for sliver_attribute in sliver_attributes: + sliver_attribute['node_id'] = nodename + attributes.append(sliver_attribute) + return attributes + + + def add_sliver_attribute(self, component_id, name, value, network=None): + nodes = self.get_nodes({'component_id': '*%s*' % component_id}) + if nodes is not None and isinstance(nodes, list) and len(nodes) > 0: + node = nodes[0] + slivers = SFAv1Sliver.get_slivers(node) + if slivers: + sliver = slivers[0] + SFAv1Sliver.add_sliver_attribute(sliver, name, value) + else: + # should this be an assert / raise an exception? + logger.error("WARNING: failed to find component_id %s" % component_id) + + def get_sliver_attributes(self, component_id, network=None): + nodes = self.get_nodes({'component_id': '*%s*' % component_id}) + attribs = [] + if nodes is not None and isinstance(nodes, list) and len(nodes) > 0: + node = nodes[0] + slivers = SFAv1Sliver.get_slivers(node.element) + if slivers is not None and isinstance(slivers, list) and len(slivers) > 0: + sliver = slivers[0] + attribs = SFAv1Sliver.get_sliver_attributes(sliver.element) + return attribs + + def remove_sliver_attribute(self, component_id, name, value, network=None): + attribs = self.get_sliver_attributes(component_id) + for attrib in attribs: + if attrib['name'] == name and attrib['value'] == value: + #attrib.element.delete() + parent = attrib.element.getparent() + parent.remove(attrib.element) + + def add_default_sliver_attribute(self, name, value, network=None): + if network: + defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network) + else: + defaults = self.xml.xpath("//sliver_defaults") + if not defaults: + if network: + network_tag = self.xml.xpath("//network[@name='%s']" % network) + else: + network_tag = self.xml.xpath("//network") + if isinstance(network_tag, list): + network_tag = network_tag[0] + defaults = network_tag.add_element('sliver_defaults') + elif isinstance(defaults, list): + defaults = defaults[0] + SFAv1Sliver.add_sliver_attribute(defaults, name, value) + + def get_default_sliver_attributes(self, network=None): + if network: + defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network) + else: + defaults = self.xml.xpath("//sliver_defaults") + if not defaults: return [] + return SFAv1Sliver.get_sliver_attributes(defaults[0]) + + def remove_default_sliver_attribute(self, name, value, network=None): + attribs = self.get_default_sliver_attributes(network) + for attrib in attribs: + if attrib['name'] == name and attrib['value'] == value: + #attrib.element.delete() + parent = attrib.element.getparent() + parent.remove(attrib.element) + + # utility + + def merge(self, in_rspec): + """ + Merge contents for specified rspec with current rspec + """ + + if not in_rspec: + return + + from sfa.rspecs.rspec import RSpec + if isinstance(in_rspec, RSpec): + rspec = in_rspec + else: + rspec = RSpec(in_rspec) + if rspec.version.type.lower() == 'protogeni': + from sfa.rspecs.rspec_converter import RSpecConverter + in_rspec = RSpecConverter.to_sfa_rspec(rspec.toxml()) + rspec = RSpec(in_rspec) + + # just copy over all networks + current_networks = self.get_networks() + networks = rspec.version.get_networks() + for network in networks: + current_network = network.get('name') + if current_network and current_network not in current_networks: + self.xml.append(network.element) + current_networks.append(current_network) + +if __name__ == '__main__': + import sys + import pprint + from sfa.rspecs.rspec import RSpec + from sfa.rspecs.rspec_elements import * + print "main ofeliav1" + if len(sys.argv)!=2: + r = RSpec('/tmp/resources.rspec') + else: + r = RSpec(sys.argv[1], version = 'OFELIA 1') + #print r.version.get_datapaths() + resources = r.version.get_resources() + pprint.pprint(resources) + + #r.load_rspec_elements(SFAv1.elements) + #print r.get(RSpecElements.NODE)