fd0e12770d8c1b194b57eb0e8ee7ee444121f7fd
[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.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
16 import os\r
17 import time\r
18 import re\r
19 \r
20 RSPEC_TMP_FILE_PREFIX = "/tmp/max_rspec"\r
21 \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
26     text = ''\r
27     while timeout:\r
28         line = pipe.read()\r
29         text += line\r
30         time.sleep(1)\r
31         timeout = timeout-1\r
32     code = pipe.close()\r
33     if code is None: code = 0\r
34     if text[-1:] == '\n': text = text[:-1]\r
35     return code, text\r
36 \r
37 """\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
42       ... params ...\r
43 """\r
44 \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
50     return ret\r
51 \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
56     file.write(rspec)\r
57     file.close()\r
58     return path\r
59 \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
64     sep = '.'\r
65     if hrn.find(':') != -1:\r
66         sep=':'\r
67     elif hrn.find('+') != -1:\r
68         sep='+'\r
69     else:\r
70         sep='.'\r
71     slice_id = hrn.split(sep)[-2] + '_' + hrn.split(sep)[-1]\r
72     return slice_id\r
73 \r
74 # extract xml \r
75 def get_xml_by_tag(text, tag):\r
76     indx1 = text.find('<'+tag)\r
77     indx2 = text.find('/'+tag+'>')\r
78     xml = None\r
79     if indx1!=-1 and indx2>indx1:\r
80         xml = text[indx1:indx2+len(tag)+2]\r
81     return xml\r
82 \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
89     slice_record=None\r
90     if users:\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
100 \r
101 def parse_resources(text, slice_xrn):\r
102     resources = []\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
106         res = {}\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
114     for vlan in vlans:\r
115         res = {}\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
122         else:\r
123             res['geni_status'] = 'configuring'\r
124         resources.append(res)\r
125     return resources\r
126 \r
127 def slice_status(api, slice_xrn, creds):\r
128     urn = hrn_to_urn(slice_xrn, 'slice')\r
129     result = {}\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
137     else:\r
138         has_failure = 0\r
139         all_active = 0\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
144              ):\r
145             top_level_status = 'configuring'\r
146         else:\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
151     return result\r
152 \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
166     # parse output ?\r
167     rspec = "<RSpec type=\"SFA\"> Done! </RSpec>"\r
168     return True\r
169 \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
173     # parse output ?\r
174     return 1\r
175 \r
176 \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
182     else:\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
188     else:\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
199     return (rspec)\r
200 \r
201 def start_slice(api, xrn, cred):\r
202     # service not supported\r
203     return None\r
204 \r
205 def stop_slice(api, xrn, cred):\r
206     # service not supported\r
207     return None\r
208 \r
209 def reset_slices(api, xrn):\r
210     # service not supported\r
211     return None\r
212 \r
213 """\r
214     GENI AM API Methods\r
215 """\r
216 \r
217 def GetVersion(api):\r
218     xrn=Xrn(api.hrn)\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
223                     'testbed':'myplc',\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
228                     }\r
229     return version_core(version_more)\r
230 \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
234 \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
239     if ret:\r
240         return get_rspec(api, creds, slice_xrn)\r
241     else:\r
242         return "<?xml version=\"1.0\" ?> <RSpec type=\"SFA\"> Error! </RSpec>"\r
243 \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
247 \r
248 # no caching\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
254 \r
255 """\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
259 """\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
263     api = SfaAPI()\r
264     create_slice(api, "plc.maxpl.test000", None, rspec_xml, None)\r
265 \r