Ofelia OpenFlow RSpec parsing support
[sfa.git] / sfa / rspecs / versions / ofeliav1.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 from copy import deepcopy
4 from lxml import etree
5
6 from sfa.util.sfalogging import logger
7 from sfa.util.xrn import hrn_to_urn, urn_to_hrn
8 from sfa.rspecs.version import RSpecVersion
9 from sfa.rspecs.elements.element import Element
10 from sfa.rspecs.elements.versions.pgv2Link import PGv2Link
11 from sfa.rspecs.elements.versions.sfav1Node import SFAv1Node
12 from sfa.rspecs.elements.versions.sfav1Sliver import SFAv1Sliver
13 from sfa.rspecs.elements.versions.sfav1Lease import SFAv1Lease
14 from sfa.rspecs.elements.versions.ofeliav1datapath import Ofeliav1Datapath
15 from sfa.rspecs.elements.versions.ofeliav1link import Ofeliav1Link
16
17 class Ofelia(RSpecVersion):
18     enabled = True
19     type = 'OFELIA'
20     content_type = '*'
21     version = '1'
22     schema = 'https://github.com/fp7-ofelia/ocf/blob/ocf.rspecs/openflow/schemas/ad.xsd'
23     namespace = 'openflow'
24     extensions = {}
25     namespaces = dict(extensions.items() + [('default', namespace)])
26     #template = '<RSpec type="%s"></RSpec>' % type
27     template = '<rspec></rspec>'
28
29     # Network 
30     def get_networks(self):
31         raise Exception, "Not implemented"
32         network_elems = self.xml.xpath('//network')
33         networks = [network_elem.get_instance(fields=['name', 'slice']) for \
34                     network_elem in network_elems]
35         return networks    
36
37
38     def add_network(self, network):
39         raise Exception, "Not implemented"
40         network_tags = self.xml.xpath('//network[@name="%s"]' % network)
41         if not network_tags:
42             network_tag = self.xml.add_element('network', name=network)
43         else:
44             network_tag = network_tags[0]
45         return network_tag
46
47 # These are all resources 
48 # get_resources function can return all resources or a specific type of resource
49     def get_resources(self, filter=None, type=None):
50         resources = list()
51         if not type or type=='datapath':
52             datapaths = self.get_datapaths(filter)
53             for datapath in datapaths:
54                 datapath['type']='datapath'
55             resources.extend(datapaths)
56         if not type or type=='link':
57             links = self.get_links(filter)
58             for link in links:
59                 link['type']='link'
60             resources.extend(links)
61         return resources
62
63     # Datapaths
64     def get_datapaths(self, filter=None):
65         return Ofeliav1Datapath.get_datapaths(self.xml, filter)
66
67     # Links
68     def get_links(self, filter=None):
69         return Ofeliav1Link.get_links(self.xml, filter)
70
71 #    def get_link_requests(self):
72 #        return PGv2Link.get_link_requests(self.xml) 
73 #
74 #    def add_links(self, links):
75 #        networks = self.get_networks()
76 #        if len(networks) > 0:
77 #            xml = networks[0].element
78 #        else:
79 #            xml = self.xml
80 #        PGv2Link.add_links(xml, links)
81 #
82 #    def add_link_requests(self, links):
83 #        PGv2Link.add_link_requests(self.xml, links)
84
85
86
87     # Slivers
88    
89     def add_slivers(self, hostnames, attributes=[], sliver_urn=None, append=False):
90         # add slice name to network tag
91         network_tags = self.xml.xpath('//network')
92         if network_tags:
93             network_tag = network_tags[0]
94             network_tag.set('slice', urn_to_hrn(sliver_urn)[0])
95
96         # add slivers
97         sliver = {'name':sliver_urn,
98                   'pl_tags': attributes}
99         for hostname in hostnames:
100             if sliver_urn:
101                 sliver['name'] = sliver_urn
102             node_elems = self.get_nodes({'component_id': '*%s*' % hostname})
103             if not node_elems:
104                 continue
105             node_elem = node_elems[0]
106             SFAv1Sliver.add_slivers(node_elem.element, sliver)
107
108         # remove all nodes without slivers
109         if not append:
110             for node_elem in self.get_nodes():
111                 if not node_elem['slivers']:
112                     parent = node_elem.element.getparent()
113                     parent.remove(node_elem.element)
114
115
116     def remove_slivers(self, slivers, network=None, no_dupes=False):
117         SFAv1Node.remove_slivers(self.xml, slivers)
118  
119     def get_slice_attributes(self, network=None):
120         attributes = []
121         nodes_with_slivers = self.get_nodes_with_slivers()
122         for default_attribute in self.get_default_sliver_attributes(network):
123             attribute = default_attribute.copy()
124             attribute['node_id'] = None
125             attributes.append(attribute)
126         for node in nodes_with_slivers:
127             nodename=node['component_name']
128             sliver_attributes = self.get_sliver_attributes(nodename, network)
129             for sliver_attribute in sliver_attributes:
130                 sliver_attribute['node_id'] = nodename
131                 attributes.append(sliver_attribute)
132         return attributes
133
134
135     def add_sliver_attribute(self, component_id, name, value, network=None):
136         nodes = self.get_nodes({'component_id': '*%s*' % component_id})
137         if nodes is not None and isinstance(nodes, list) and len(nodes) > 0:
138             node = nodes[0]
139             slivers = SFAv1Sliver.get_slivers(node)
140             if slivers:
141                 sliver = slivers[0]
142                 SFAv1Sliver.add_sliver_attribute(sliver, name, value)
143         else:
144             # should this be an assert / raise an exception?
145             logger.error("WARNING: failed to find component_id %s" % component_id)
146
147     def get_sliver_attributes(self, component_id, network=None):
148         nodes = self.get_nodes({'component_id': '*%s*' % component_id})
149         attribs = []
150         if nodes is not None and isinstance(nodes, list) and len(nodes) > 0:
151             node = nodes[0]
152             slivers = SFAv1Sliver.get_slivers(node.element)
153             if slivers is not None and isinstance(slivers, list) and len(slivers) > 0:
154                 sliver = slivers[0]
155                 attribs = SFAv1Sliver.get_sliver_attributes(sliver.element)
156         return attribs
157
158     def remove_sliver_attribute(self, component_id, name, value, network=None):
159         attribs = self.get_sliver_attributes(component_id)
160         for attrib in attribs:
161             if attrib['name'] == name and attrib['value'] == value:
162                 #attrib.element.delete()
163                 parent = attrib.element.getparent()
164                 parent.remove(attrib.element)
165
166     def add_default_sliver_attribute(self, name, value, network=None):
167         if network:
168             defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network)
169         else:
170             defaults = self.xml.xpath("//sliver_defaults")
171         if not defaults:
172             if network:
173                 network_tag = self.xml.xpath("//network[@name='%s']" % network)
174             else:
175                 network_tag = self.xml.xpath("//network")    
176             if isinstance(network_tag, list):
177                 network_tag = network_tag[0]
178             defaults = network_tag.add_element('sliver_defaults')
179         elif isinstance(defaults, list):
180             defaults = defaults[0]
181         SFAv1Sliver.add_sliver_attribute(defaults, name, value)
182
183     def get_default_sliver_attributes(self, network=None):
184         if network:
185             defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network)
186         else:
187             defaults = self.xml.xpath("//sliver_defaults")
188         if not defaults: return []
189         return SFAv1Sliver.get_sliver_attributes(defaults[0])
190     
191     def remove_default_sliver_attribute(self, name, value, network=None):
192         attribs = self.get_default_sliver_attributes(network)
193         for attrib in attribs:
194             if attrib['name'] == name and attrib['value'] == value:
195                 #attrib.element.delete()
196                 parent = attrib.element.getparent()
197                 parent.remove(attrib.element)
198
199     # utility
200
201     def merge(self, in_rspec):
202         """
203         Merge contents for specified rspec with current rspec
204         """
205
206         if not in_rspec:
207             return
208
209         from sfa.rspecs.rspec import RSpec
210         if isinstance(in_rspec, RSpec):
211             rspec = in_rspec
212         else:
213             rspec = RSpec(in_rspec)
214         if rspec.version.type.lower() == 'protogeni':
215             from sfa.rspecs.rspec_converter import RSpecConverter
216             in_rspec = RSpecConverter.to_sfa_rspec(rspec.toxml())
217             rspec = RSpec(in_rspec)
218
219         # just copy over all networks
220         current_networks = self.get_networks()
221         networks = rspec.version.get_networks()
222         for network in networks:
223             current_network = network.get('name')
224             if current_network and current_network not in current_networks:
225                 self.xml.append(network.element)
226                 current_networks.append(current_network)
227
228 if __name__ == '__main__':
229     import sys
230     import pprint
231     from sfa.rspecs.rspec import RSpec
232     from sfa.rspecs.rspec_elements import *
233     print "main ofeliav1"
234     if len(sys.argv)!=2:
235         r = RSpec('/tmp/resources.rspec')
236     else:
237         r = RSpec(sys.argv[1], version = 'OFELIA 1')
238     #print r.version.get_datapaths()
239     resources = r.version.get_resources()
240     pprint.pprint(resources)
241
242     #r.load_rspec_elements(SFAv1.elements)
243     #print r.get(RSpecElements.NODE)