5 from sfa.util.faults import *
6 from sfa.util.sfalogging import logger
7 from sfa.util.config import Config
8 from sfa.util.sfatime import utcparse
9 from sfa.util.callids import Callids
10 from sfa.util.version import version_core
11 from sfa.util.xrn import urn_to_hrn, hrn_to_urn, get_authority, Xrn
12 from sfa.util.plxrn import hrn_to_pl_slicename
14 from sfa.server.sfaapi import SfaApi
15 from sfa.server.registry import Registries
16 from sfa.rspecs.rspec_version import RSpecVersion
17 from sfa.rspecs.sfa_rspec import sfa_rspec_version
18 from sfa.rspecs.rspec_parser import parse_rspec
20 from sfa.managers.aggregate_manager import _get_registry_objects, ListSlices
22 from sfa.plc.slices import Slices
25 RSPEC_TMP_FILE_PREFIX = "/tmp/max_rspec"
27 # execute shell command and return both exit code and text output
28 def shell_execute(cmd, timeout):
29 pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
30 pipe = os.popen(cmd + ' 2>&1', 'r')
38 if code is None: code = 0
39 if text[-1:] == '\n': text = text[:-1]
43 call AM API client with command like in the following example:
44 cd aggregate_client; java -classpath AggregateWS-client-api.jar:lib/* \
45 net.geni.aggregate.client.examples.CreateSliceNetworkClient \
46 ./repo https://geni:8443/axis2/services/AggregateGENI \
50 def call_am_apiclient(client_app, params, timeout):
51 (client_path, am_url) = Config().get_max_aggrMgr_info()
52 sys_cmd = "cd " + client_path + "; java -classpath AggregateWS-client-api.jar:lib/* net.geni.aggregate.client.examples." + client_app + " ./repo " + am_url + " " + ' '.join(params)
53 ret = shell_execute(sys_cmd, timeout)
54 logger.debug("shell_execute cmd: %s returns %s" % (sys_cmd, ret))
57 # save request RSpec xml content to a tmp file
58 def save_rspec_to_file(rspec):
59 path = RSPEC_TMP_FILE_PREFIX + "_" + time.strftime('%Y%m%dT%H:%M:%S', time.gmtime(time.time())) +".xml"
60 file = open(path, "w")
65 # get stripped down slice id/name plc.maxpl.xislice1 --> maxpl_xislice1
66 def get_plc_slice_id(cred, xrn):
67 (hrn, type) = urn_to_hrn(xrn)
68 slice_id = hrn.find(':')
70 if hrn.find(':') != -1:
72 elif hrn.find('+') != -1:
76 slice_id = hrn.split(sep)[-2] + '_' + hrn.split(sep)[-1]
80 def get_xml_by_tag(text, tag):
81 indx1 = text.find('<'+tag)
82 indx2 = text.find('/'+tag+'>')
84 if indx1!=-1 and indx2>indx1:
85 xml = text[indx1:indx2+len(tag)+2]
88 def prepare_slice(api, slice_xrn, creds, users):
89 reg_objects = _get_registry_objects(slice_xrn, creds, users)
90 (hrn, type) = urn_to_hrn(slice_xrn)
92 peer = slices.get_peer(hrn)
93 sfa_peer = slices.get_sfa_peer(hrn)
96 slice_record = users[0].get('slice_record', {})
97 registry = api.registries[api.hrn]
98 credential = api.getCredential()
99 # ensure site record exists
100 site = slices.verify_site(hrn, slice_record, peer, sfa_peer)
101 # ensure slice record exists
102 slice = slices.verify_slice(hrn, slice_record, peer, sfa_peer)
103 # ensure person records exists
104 persons = slices.verify_persons(hrn, slice, users, peer, sfa_peer)
106 def parse_resources(text, slice_xrn):
108 urn = hrn_to_urn(slice_xrn, 'sliver')
109 plc_slice = re.search("Slice Status => ([^\n]+)", text)
110 if plc_slice.group(1) != 'NONE':
112 res['geni_urn'] = urn + '_plc_slice'
113 res['geni_error'] = ''
114 res['geni_status'] = 'unknown'
115 if plc_slice.group(1) == 'CREATED':
116 res['geni_status'] = 'ready'
117 resources.append(res)
118 vlans = re.findall("GRI => ([^\n]+)\n\t Status => ([^\n]+)", text)
121 res['geni_error'] = ''
122 res['geni_urn'] = urn + '_vlan_' + vlan[0]
123 if vlan[1] == 'ACTIVE':
124 res['geni_status'] = 'ready'
125 elif vlan[1] == 'FAILED':
126 res['geni_status'] = 'failed'
128 res['geni_status'] = 'configuring'
129 resources.append(res)
132 def slice_status(api, slice_xrn, creds):
133 urn = hrn_to_urn(slice_xrn, 'slice')
135 top_level_status = 'unknown'
136 slice_id = get_plc_slice_id(creds, urn)
137 (ret, output) = call_am_apiclient("QuerySliceNetworkClient", [slice_id,], 5)
138 # parse output into rspec XML
139 if output.find("Unkown Rspec:") > 0:
140 top_level_staus = 'failed'
141 result['geni_resources'] = ''
145 if output.find("Status => FAILED") > 0:
146 top_level_staus = 'failed'
147 elif ( output.find("Status => ACCEPTED") > 0 or output.find("Status => PENDING") > 0
148 or output.find("Status => INSETUP") > 0 or output.find("Status => INCREATE") > 0
150 top_level_status = 'configuring'
152 top_level_status = 'ready'
153 result['geni_resources'] = parse_resources(output, slice_xrn)
154 result['geni_urn'] = urn
155 result['geni_status'] = top_level_status
158 def create_slice(api, xrn, cred, rspec, users):
159 indx1 = rspec.find("<RSpec")
160 indx2 = rspec.find("</RSpec>")
161 if indx1 > -1 and indx2 > indx1:
162 rspec = rspec[indx1+len("<RSpec type=\"SFA\">"):indx2-1]
163 rspec_path = save_rspec_to_file(rspec)
164 prepare_slice(api, xrn, cred, users)
165 slice_id = get_plc_slice_id(cred, xrn)
166 sys_cmd = "sed -i \"s/rspec id=\\\"[^\\\"]*/rspec id=\\\"" +slice_id+ "/g\" " + rspec_path + ";sed -i \"s/:rspec=[^:'<\\\" ]*/:rspec=" +slice_id+ "/g\" " + rspec_path
167 ret = shell_execute(sys_cmd, 1)
168 sys_cmd = "sed -i \"s/rspec id=\\\"[^\\\"]*/rspec id=\\\"" + rspec_path + "/g\""
169 ret = shell_execute(sys_cmd, 1)
170 (ret, output) = call_am_apiclient("CreateSliceNetworkClient", [rspec_path,], 3)
172 rspec = "<RSpec type=\"SFA\"> Done! </RSpec>"
175 def delete_slice(api, xrn, cred):
176 slice_id = get_plc_slice_id(cred, xrn)
177 (ret, output) = call_am_apiclient("DeleteSliceNetworkClient", [slice_id,], 3)
182 def get_rspec(api, cred, slice_urn):
183 logger.debug("#### called max-get_rspec")
184 #geni_slice_urn: urn:publicid:IDN+plc:maxpl+slice+xi_rspec_test1
185 if slice_urn == None:
186 (ret, output) = call_am_apiclient("GetResourceTopology", ['all', '\"\"'], 5)
188 slice_id = get_plc_slice_id(cred, slice_urn)
189 (ret, output) = call_am_apiclient("GetResourceTopology", ['all', slice_id,], 5)
190 # parse output into rspec XML
191 if output.find("No resouce found") > 0:
192 rspec = "<RSpec type=\"SFA\"> <Fault>No resource found</Fault> </RSpec>"
194 comp_rspec = get_xml_by_tag(output, 'computeResource')
195 logger.debug("#### computeResource %s" % comp_rspec)
196 topo_rspec = get_xml_by_tag(output, 'topology')
197 logger.debug("#### topology %s" % topo_rspec)
198 rspec = "<RSpec type=\"SFA\"> <network name=\"" + Config().get_interface_hrn() + "\">";
199 if comp_rspec != None:
200 rspec = rspec + get_xml_by_tag(output, 'computeResource')
201 if topo_rspec != None:
202 rspec = rspec + get_xml_by_tag(output, 'topology')
203 rspec = rspec + "</network> </RSpec>"
206 def start_slice(api, xrn, cred):
207 # service not supported
210 def stop_slice(api, xrn, cred):
211 # service not supported
214 def reset_slices(api, xrn):
215 # service not supported
224 request_rspec_versions = [dict(sfa_rspec_version)]
225 ad_rspec_versions = [dict(sfa_rspec_version)]
226 #TODO: MAX-AM specific
227 version_more = {'interface':'aggregate',
230 'request_rspec_versions': request_rspec_versions,
231 'ad_rspec_versions': ad_rspec_versions,
232 'default_ad_rspec': dict(sfa_rspec_version)
234 return version_core(version_more)
236 def SliverStatus(api, slice_xrn, creds, call_id):
237 if Callids().already_handled(call_id): return {}
238 return slice_status(api, slice_xrn, creds)
240 def CreateSliver(api, slice_xrn, creds, rspec_string, users, call_id):
241 if Callids().already_handled(call_id): return ""
242 #TODO: create real CreateSliver response rspec
243 ret = create_slice(api, slice_xrn, creds, rspec_string, users)
245 return get_rspec(api, creds, slice_xrn)
247 return "<?xml version=\"1.0\" ?> <RSpec type=\"SFA\"> Error! </RSpec>"
249 def DeleteSliver(api, xrn, creds, call_id):
250 if Callids().already_handled(call_id): return ""
251 return delete_slice(api, xrn, creds)
254 def ListResources(api, creds, options,call_id):
255 if Callids().already_handled(call_id): return ""
256 # version_string = "rspec_%s" % (rspec_version.get_version_name())
257 slice_urn = options.get('geni_slice_urn')
258 return get_rspec(api, creds, slice_urn)
260 def fetch_context(slice_hrn, user_hrn, contexts):
262 Returns the request context required by sfatables. At some point, this mechanism should be changed
263 to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
264 return the basic information needed in a dict.
266 base_context = {'sfa':{'user':{'hrn':user_hrn}}}
269 create_slice(api, "plc.maxpl.test000", None, rspec_xml, None)