refactored
[sfa.git] / sfa / rspecs / versions / sfav1.py
1 from copy import deepcopy
2 from lxml import etree
3 from sfa.util.xrn import hrn_to_urn, urn_to_hrn
4 from sfa.util.plxrn import PlXrn
5 from sfa.rspecs.rspec_version import BaseVersion
6 from sfa.rspecs.rspec_elements import RSpecElement, RSpecElements
7 from sfa.rspecs.elements.versions.pgv2Link import PGv2Link
8 from sfa.rspecs.elements.versions.sfav1Node import SFAv1Node
9
10 class SFAv1(BaseVersion):
11     enabled = True
12     type = 'SFA'
13     content_type = '*'
14     version = '1'
15     schema = None
16     namespace = None
17     extensions = {}
18     namespaces = None
19     elements = [] 
20     template = '<RSpec type="%s"></RSpec>' % type
21
22     def get_network_elements(self):
23         return self.xml.xpath('//network')
24
25     def get_networks(self):
26         return self.xml.xpath('//network[@name]/@name')
27
28     def get_nodes(self, network=None):
29         return SFAv1Node.get_nodes(self.xml)
30
31     def get_nodes_with_slivers(self, network = None):
32         return SFAv1Node.get_nodes_with_slivers(self.xml)
33
34     def attributes_list(self, elem):
35         # convert a list of attribute tags into list of tuples
36         # (tagnme, text_value)
37         opts = []
38         if elem is not None:
39             for e in elem:
40                 opts.append((e.tag, str(e.text).strip()))
41         return opts
42
43     def get_default_sliver_attributes(self, network=None):
44         if network:
45             defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network)
46         else:
47             defaults = self.xml.xpath("//sliver_defaults")
48         if isinstance(defaults, list) and defaults:
49             defaults = defaults[0]
50         return self.attributes_list(defaults)
51
52     def get_sliver_attributes(self, hostname, network=None):
53         attributes = []
54         node = self.get_node_element(hostname, network)
55         #sliver = node.find("sliver")
56         slivers = node.xpath('./sliver')
57         if isinstance(slivers, list) and slivers:
58             attributes = self.attributes_list(slivers[0])
59         return attributes
60
61     def get_slice_attributes(self, network=None):
62         slice_attributes = []
63         nodes_with_slivers = self.get_nodes_with_slivers(network)
64         for default_attribute in self.get_default_sliver_attributes(network):
65             attribute = {'name': str(default_attribute[0]), 'value': str(default_attribute[1]), 'node_id': None}
66             slice_attributes.append(attribute)
67         for node in nodes_with_slivers:
68             sliver_attributes = self.get_sliver_attributes(node, network)
69             for sliver_attribute in sliver_attributes:
70                 attribute = {'name': str(sliver_attribute[0]), 'value': str(sliver_attribute[1]), 'node_id': node}
71                 slice_attributes.append(attribute)
72         return slice_attributes
73
74     def get_links(self, network=None):
75         return PGv2Link.get_links(self.xml)
76
77     def get_link_requests(self):
78         return PGv2Link.get_link_requests(self.xml) 
79
80     ##################
81     # Builder
82     ##################
83
84     def add_network(self, network):
85         network_tags = self.xml.xpath('//network[@name="%s"]' % network)
86         if not network_tags:
87             network_tag = etree.SubElement(self.xml.root, 'network', name=network)
88         else:
89             network_tag = network_tags[0]
90         return network_tag
91
92     def add_nodes(self, nodes, network = None, no_dupes=False):
93         SFAv1Node.add_nodes(self.xml, nodes)
94
95     def merge_node(self, source_node_tag, network, no_dupes=False):
96         if no_dupes and self.get_node_element(node['hostname']):
97             # node already exists
98             return
99
100         network_tag = self.add_network(network)
101         network_tag.append(deepcopy(source_node_tag))
102
103     def add_links(self, links):
104         networks = self.get_network_elements()
105         if len(networks) > 0:
106             xml = networks[0]
107         else:
108             xml = self.xml    
109         PGv2Link.add_links(xml, links)
110
111     def add_link_requests(self, links):
112         PGv2Link.add_link_requests(self.xml, links)
113
114     def add_slivers(self, slivers, network=None, sliver_urn=None, no_dupes=False, append=False):
115         # add slice name to network tag
116         network_tags = self.xml.xpath('//network')
117         if network_tags:
118             network_tag = network_tags[0]
119             network_tag.set('slice', urn_to_hrn(sliver_urn)[0])
120         
121         all_nodes = self.get_nodes()
122         nodes_with_slivers = [sliver['hostname'] for sliver in slivers]
123         nodes_without_slivers = set(all_nodes).difference(nodes_with_slivers)
124         
125         # add slivers
126         for sliver in slivers:
127             node_elem = self.get_node_element(sliver['hostname'], network)
128             if not node_elem: continue
129             sliver_elem = etree.SubElement(node_elem, 'sliver')
130             if 'tags' in sliver:
131                 for tag in sliver['tags']:
132                     etree.SubElement(sliver_elem, tag['tagname']).text = value=tag['value']
133             
134         # remove all nodes without slivers
135         if not append:
136             for node in nodes_without_slivers:
137                 node_elem = self.get_node_element(node)
138                 parent = node_elem.getparent()
139                 parent.remove(node_elem)
140
141     def remove_slivers(self, slivers, network=None, no_dupes=False):
142         SFAv1Node.remove_slivers(self.xml, slivers)
143
144     def add_default_sliver_attribute(self, name, value, network=None):
145         if network:
146             defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network)
147         else:
148             defaults = self.xml.xpath("//sliver_defaults" % network)
149         if not defaults :
150             network_tag = self.xml.xpath("//network[@name='%s']" % network)
151             if isinstance(network_tag, list):
152                 network_tag = network_tag[0]
153             defaults = self.xml.add_element('sliver_defaults', attrs={}, parent=network_tag)
154         elif isinstance(defaults, list):
155             defaults = defaults[0]
156         self.xml.add_attribute(defaults, name, value)
157
158     def add_sliver_attribute(self, hostname, name, value, network=None):
159         node = self.get_node_element(hostname, network)
160         sliver = node.find("sliver")
161         self.xml.add_attribute(sliver, name, value)
162
163     def remove_default_sliver_attribute(self, name, value, network=None):
164         if network:
165             defaults = self.xml.xpath("//network[@name='%s']/sliver_defaults" % network)
166         else:
167             defaults = self.xml.xpath("//sliver_defaults" % network)
168         self.xml.remove_attribute(defaults, name, value)
169
170     def remove_sliver_attribute(self, hostname, name, value, network=None):
171         node = self.get_node_element(hostname, network)
172         sliver = node.find("sliver")
173         self.xml.remove_attribute(sliver, name, value)
174
175     def merge(self, in_rspec):
176         """
177         Merge contents for specified rspec with current rspec
178         """
179
180         from sfa.rspecs.rspec import RSpec
181         if isinstance(in_rspec, RSpec):
182             rspec = in_rspec
183         else:
184             rspec = RSpec(in_rspec)
185         if rspec.version.type.lower() == 'protogeni':
186             from sfa.rspecs.rspec_converter import RSpecConverter
187             in_rspec = RSpecConverter.to_sfa_rspec(rspec.toxml())
188             rspec = RSpec(in_rspec)
189
190         # just copy over all networks
191         current_networks = self.get_networks()
192         networks = rspec.version.get_network_elements()
193         for network in networks:
194             current_network = network.get('name')
195             if current_network and current_network not in current_networks:
196                 self.xml.root.append(network)
197                 current_networks.append(current_network)
198
199 if __name__ == '__main__':
200     from sfa.rspecs.rspec import RSpec
201     from sfa.rspecs.rspec_elements import *
202     r = RSpec('/tmp/resources.rspec')
203     r.load_rspec_elements(SFAv1.elements)
204     print r.get(RSpecElements.NODE)