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