1 from sfa.plc.slices import Slices
\r
2 from sfa.server.registry import Registries
\r
3 from sfa.util.xrn import urn_to_hrn, hrn_to_urn, get_authority, Xrn
\r
4 from sfa.util.plxrn import hrn_to_pl_slicename
\r
5 from sfa.util.rspec import RSpec
\r
6 from sfa.util.sfalogging import logger
\r
7 from sfa.util.faults import *
\r
8 from sfa.util.config import Config
\r
9 from sfa.util.sfatime import utcparse
\r
10 from sfa.util.callids import Callids
\r
11 from sfa.util.version import version_core
\r
12 from sfa.rspecs.rspec_version import RSpecVersion
\r
13 from sfa.rspecs.sfa_rspec import sfa_rspec_version
\r
14 from sfa.rspecs.rspec_parser import parse_rspec
\r
15 from sfa.managers.aggregate_manager_pl import __get_registry_objects, ListSlices
\r
20 RSPEC_TMP_FILE_PREFIX = "/tmp/max_rspec"
\r
22 # execute shell command and return both exit code and text output
\r
23 def shell_execute(cmd, timeout):
\r
24 pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
\r
25 pipe = os.popen(cmd + ' 2>&1', 'r')
\r
33 if code is None: code = 0
\r
34 if text[-1:] == '\n': text = text[:-1]
\r
38 call AM API client with command like in the following example:
\r
39 cd aggregate_client; java -classpath AggregateWS-client-api.jar:lib/* \
\r
40 net.geni.aggregate.client.examples.CreateSliceNetworkClient \
\r
41 ./repo https://geni:8443/axis2/services/AggregateGENI \
\r
45 def call_am_apiclient(client_app, params, timeout):
\r
46 (client_path, am_url) = Config().get_max_aggrMgr_info()
\r
47 sys_cmd = "cd " + client_path + "; java -classpath AggregateWS-client-api.jar:lib/* net.geni.aggregate.client.examples." + client_app + " ./repo " + am_url + " " + ' '.join(params)
\r
48 ret = shell_execute(sys_cmd, timeout)
\r
49 logger.debug("shell_execute cmd: %s returns %s" % (sys_cmd, ret))
\r
52 # save request RSpec xml content to a tmp file
\r
53 def save_rspec_to_file(rspec):
\r
54 path = RSPEC_TMP_FILE_PREFIX + "_" + time.strftime('%Y%m%dT%H:%M:%S', time.gmtime(time.time())) +".xml"
\r
55 file = open(path, "w")
\r
60 # get stripped down slice id/name plc.maxpl.xislice1 --> maxpl_xislice1
\r
61 def get_plc_slice_id(cred, xrn):
\r
62 (hrn, type) = urn_to_hrn(xrn)
\r
63 slice_id = hrn.find(':')
\r
65 if hrn.find(':') != -1:
\r
67 elif hrn.find('+') != -1:
\r
71 slice_id = hrn.split(sep)[-2] + '_' + hrn.split(sep)[-1]
\r
75 def get_xml_by_tag(text, tag):
\r
76 indx1 = text.find('<'+tag)
\r
77 indx2 = text.find('/'+tag+'>')
\r
79 if indx1!=-1 and indx2>indx1:
\r
80 xml = text[indx1:indx2+len(tag)+2]
\r
83 def prepare_slice(api, slice_xrn, creds, users):
\r
84 reg_objects = __get_registry_objects(slice_xrn, creds, users)
\r
85 (hrn, type) = urn_to_hrn(slice_xrn)
\r
86 slices = Slices(api)
\r
87 peer = slices.get_peer(hrn)
\r
88 sfa_peer = slices.get_sfa_peer(hrn)
\r
91 slice_record = users[0].get('slice_record', {})
\r
92 registry = api.registries[api.hrn]
\r
93 credential = api.getCredential()
\r
94 # ensure site record exists
\r
95 site = slices.verify_site(hrn, slice_record, peer, sfa_peer)
\r
96 # ensure slice record exists
\r
97 slice = slices.verify_slice(hrn, slice_record, peer, sfa_peer)
\r
98 # ensure person records exists
\r
99 persons = slices.verify_persons(hrn, slice, users, peer, sfa_peer)
\r
101 def parse_resources(text, slice_xrn):
\r
103 urn = hrn_to_urn(slice_xrn, 'sliver')
\r
104 plc_slice = re.search("Slice Status => ([^\n]+)", text)
\r
105 if plc_slice.group(1) != 'NONE':
\r
107 res['geni_urn'] = urn + '_plc_slice'
\r
108 res['geni_error'] = ''
\r
109 res['geni_status'] = 'unknown'
\r
110 if plc_slice.group(1) == 'CREATED':
\r
111 res['geni_status'] = 'ready'
\r
112 resources.append(res)
\r
113 vlans = re.findall("GRI => ([^\n]+)\n\t Status => ([^\n]+)", text)
\r
116 res['geni_error'] = ''
\r
117 res['geni_urn'] = urn + '_vlan_' + vlan[0]
\r
118 if vlan[1] == 'ACTIVE':
\r
119 res['geni_status'] = 'ready'
\r
120 elif vlan[1] == 'FAILED':
\r
121 res['geni_status'] = 'failed'
\r
123 res['geni_status'] = 'configuring'
\r
124 resources.append(res)
\r
127 def slice_status(api, slice_xrn, creds):
\r
128 urn = hrn_to_urn(slice_xrn, 'slice')
\r
130 top_level_status = 'unknown'
\r
131 slice_id = get_plc_slice_id(creds, urn)
\r
132 (ret, output) = call_am_apiclient("QuerySliceNetworkClient", [slice_id,], 5)
\r
133 # parse output into rspec XML
\r
134 if output.find("Unkown Rspec:") > 0:
\r
135 top_level_staus = 'failed'
\r
136 result['geni_resources'] = ''
\r
140 if output.find("Status => FAILED") > 0:
\r
141 top_level_staus = 'failed'
\r
142 elif ( output.find("Status => ACCEPTED") > 0 or output.find("Status => PENDING") > 0
\r
143 or output.find("Status => INSETUP") > 0 or output.find("Status => INCREATE") > 0
\r
145 top_level_status = 'configuring'
\r
147 top_level_status = 'ready'
\r
148 result['geni_resources'] = parse_resources(output, slice_xrn)
\r
149 result['geni_urn'] = urn
\r
150 result['geni_status'] = top_level_status
\r
153 def create_slice(api, xrn, cred, rspec, users):
\r
154 indx1 = rspec.find("<RSpec")
\r
155 indx2 = rspec.find("</RSpec>")
\r
156 if indx1 > -1 and indx2 > indx1:
\r
157 rspec = rspec[indx1+len("<RSpec type=\"SFA\">"):indx2-1]
\r
158 rspec_path = save_rspec_to_file(rspec)
\r
159 prepare_slice(api, xrn, cred, users)
\r
160 slice_id = get_plc_slice_id(cred, xrn)
\r
161 sys_cmd = "sed -i \"s/rspec id=\\\"[^\\\"]*/rspec id=\\\"" +slice_id+ "/g\" " + rspec_path + ";sed -i \"s/:rspec=[^:'<\\\" ]*/:rspec=" +slice_id+ "/g\" " + rspec_path
\r
162 ret = shell_execute(sys_cmd, 1)
\r
163 sys_cmd = "sed -i \"s/rspec id=\\\"[^\\\"]*/rspec id=\\\"" + rspec_path + "/g\""
\r
164 ret = shell_execute(sys_cmd, 1)
\r
165 (ret, output) = call_am_apiclient("CreateSliceNetworkClient", [rspec_path,], 3)
\r
167 rspec = "<RSpec type=\"SFA\"> Done! </RSpec>"
\r
170 def delete_slice(api, xrn, cred):
\r
171 slice_id = get_plc_slice_id(cred, xrn)
\r
172 (ret, output) = call_am_apiclient("DeleteSliceNetworkClient", [slice_id,], 3)
\r
177 def get_rspec(api, cred, slice_urn):
\r
178 logger.debug("#### called max-get_rspec")
\r
179 #geni_slice_urn: urn:publicid:IDN+plc:maxpl+slice+xi_rspec_test1
\r
180 if slice_urn == None:
\r
181 (ret, output) = call_am_apiclient("GetResourceTopology", ['all', '\"\"'], 5)
\r
183 slice_id = get_plc_slice_id(cred, slice_urn)
\r
184 (ret, output) = call_am_apiclient("GetResourceTopology", ['all', slice_id,], 5)
\r
185 # parse output into rspec XML
\r
186 if output.find("No resouce found") > 0:
\r
187 rspec = "<RSpec type=\"SFA\"> <Fault>No resource found</Fault> </RSpec>"
\r
189 comp_rspec = get_xml_by_tag(output, 'computeResource')
\r
190 logger.debug("#### computeResource %s" % comp_rspec)
\r
191 topo_rspec = get_xml_by_tag(output, 'topology')
\r
192 logger.debug("#### topology %s" % topo_rspec)
\r
193 rspec = "<RSpec type=\"SFA\"> <network name=\"" + Config().get_interface_hrn() + "\">";
\r
194 if comp_rspec != None:
\r
195 rspec = rspec + get_xml_by_tag(output, 'computeResource')
\r
196 if topo_rspec != None:
\r
197 rspec = rspec + get_xml_by_tag(output, 'topology')
\r
198 rspec = rspec + "</network> </RSpec>"
\r
201 def start_slice(api, xrn, cred):
\r
202 # service not supported
\r
205 def stop_slice(api, xrn, cred):
\r
206 # service not supported
\r
209 def reset_slices(api, xrn):
\r
210 # service not supported
\r
214 GENI AM API Methods
\r
217 def GetVersion(api):
\r
219 request_rspec_versions = [dict(sfa_rspec_version)]
\r
220 ad_rspec_versions = [dict(sfa_rspec_version)]
\r
221 #TODO: MAX-AM specific
\r
222 version_more = {'interface':'aggregate',
\r
224 'hrn':xrn.get_hrn(),
\r
225 'request_rspec_versions': request_rspec_versions,
\r
226 'ad_rspec_versions': ad_rspec_versions,
\r
227 'default_ad_rspec': dict(sfa_rspec_version)
\r
229 return version_core(version_more)
\r
231 def SliverStatus(api, slice_xrn, creds, call_id):
\r
232 if Callids().already_handled(call_id): return {}
\r
233 return slice_status(api, slice_xrn, creds)
\r
235 def CreateSliver(api, slice_xrn, creds, rspec_string, users, call_id):
\r
236 if Callids().already_handled(call_id): return ""
\r
237 #TODO: create real CreateSliver response rspec
\r
238 ret = create_slice(api, slice_xrn, creds, rspec_string, users)
\r
240 return get_rspec(api, creds, slice_xrn)
\r
242 return "<?xml version=\"1.0\" ?> <RSpec type=\"SFA\"> Error! </RSpec>"
\r
244 def DeleteSliver(api, xrn, creds, call_id):
\r
245 if Callids().already_handled(call_id): return ""
\r
246 return delete_slice(api, xrn, creds)
\r
249 def ListResources(api, creds, options,call_id):
\r
250 if Callids().already_handled(call_id): return ""
\r
251 # version_string = "rspec_%s" % (rspec_version.get_version_name())
\r
252 slice_urn = options.get('geni_slice_urn')
\r
253 return get_rspec(api, creds, slice_urn)
\r
256 Returns the request context required by sfatables. At some point, this mechanism should be changed
\r
257 to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
\r
258 return the basic information needed in a dict.
\r
260 def fetch_context(slice_hrn, user_hrn, contexts):
\r
261 base_context = {'sfa':{'user':{'hrn':user_hrn}}}
\r
262 return base_context
\r
264 create_slice(api, "plc.maxpl.test000", None, rspec_xml, None)
\r