really fixed the redundant logging issue this time.
[sfa.git] / sfa / managers / aggregate_manager_max.py
1 from sfa.util.xrn import urn_to_hrn, hrn_to_urn, get_authority
2 from sfa.util.plxrn import hrn_to_pl_slicename
3 from sfa.util.plxrn import hrn_to_pl_slicename
4 from sfa.util.rspec import RSpec
5 from sfa.util.sfalogging import logger
6 from sfa.util.config import Config
7 from sfa.managers.aggregate_manager_pl import GetVersion, __get_registry_objects
8 from sfa.plc.slices import Slices
9 import os
10 import time
11
12 RSPEC_TMP_FILE_PREFIX = "/tmp/max_rspec"
13
14 # execute shell command and return both exit code and text output
15 def shell_execute(cmd, timeout):
16     pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
17     pipe = os.popen(cmd + ' 2>&1', 'r')
18     text = ''
19     while timeout:
20         line = pipe.read()
21         text += line
22         time.sleep(1)
23         timeout = timeout-1
24     code = pipe.close()
25     if code is None: code = 0
26     if text[-1:] == '\n': text = text[:-1]
27     return code, text
28
29 """
30  call AM API client with command like in the following example:
31  cd aggregate_client; java -classpath AggregateWS-client-api.jar:lib/* \
32       net.geni.aggregate.client.examples.CreateSliceNetworkClient \
33       ./repo https://geni:8443/axis2/services/AggregateGENI \
34       ... params ...
35 """
36
37 def call_am_apiclient(client_app, params, timeout):
38     (client_path, am_url) = Config().get_max_aggrMgr_info()
39     sys_cmd = "cd " + client_path + "; java -classpath AggregateWS-client-api.jar:lib/* net.geni.aggregate.client.examples." + client_app + " ./repo " + am_url + " " + ' '.join(params)
40     ret = shell_execute(sys_cmd, timeout)
41     logger.debug("shell_execute cmd: %s returns %s" % (sys_cmd, ret))
42 # save request RSpec xml content to a tmp file
43 def save_rspec_to_file(rspec):
44     path = RSPEC_TMP_FILE_PREFIX + "_" + time.strftime('%Y%m%dT%H:%M:%S', time.gmtime(time.time())) +".xml"
45     file = open(path, "w")
46     file.write(rspec)
47     file.close()
48     return path
49
50 # get stripped down slice id/name plc:maxpl:xi_slice1 --> xi_slice1
51 def get_short_slice_id(cred, hrn):
52     if hrn == None:
53         return None
54     slice_id = hrn[hrn.rfind('+')+1:]
55     if slice_id == None:
56         slice_id = hrn[hrn.rfind(':')+1:]
57     if slice_id == None:
58        return hrn
59        pass
60     return str(slice_id)
61
62 # extract xml 
63 def get_xml_by_tag(text, tag):
64     indx1 = text.find('<'+tag)
65     indx2 = text.find('/'+tag+'>')
66     xml = None
67     if indx1!=-1 and indx2>indx1:
68         xml = text[indx1:indx2+len(tag)+2]
69     return xml
70
71 def prepare_slice(api, xrn, users):
72     reg_objects = __get_registry_objects(slice_xrn, creds, users)
73     (hrn, type) = urn_to_hrn(slice_xrn)
74     slices = Slices(api)
75     peer = slices.get_peer(hrn)
76     sfa_peer = slices.get_sfa_peer(hrn)
77     registry = api.registries[api.hrn]
78     credential = api.getCredential()
79     (site_id, remote_site_id) = slices.verify_site(registry, credential, hrn, peer, sfa_peer, reg_objects)
80     slices.verify_slice(registry, credential, hrn, site_id, remote_site_id, peer, sfa_peer, reg_objects)
81
82 def create_slice(api, xrn, cred, rspec, users):
83     indx1 = rspec.find("<RSpec")
84     indx2 = rspec.find("</RSpec>")
85     if indx1 > -1 and indx2 > indx1:
86         rspec = rspec[indx1+len("<RSpec type=\"SFA\">"):indx2-1]
87     rspec_path = save_rspec_to_file(rspec)
88     prepare_slice(api, xrn, users)
89     (ret, output) = call_am_apiclient("CreateSliceNetworkClient", [rspec_path,], 3)
90     # parse output ?
91     rspec = "<RSpec type=\"SFA\"> Done! </RSpec>"
92 def delete_slice(api, xrn, cred):
93     slice_id = get_short_slice_id(cred, xrn)
94     (ret, output) = call_am_apiclient("DeleteSliceNetworkClient", [slice_id,], 3)
95     # parse output ?
96 def get_rspec(api, cred, options):
97     #geni_slice_urn: urn:publicid:IDN+plc:maxpl+slice+xi_rspec_test1
98     urn = options.get('geni_slice_urn')
99     slice_id = get_short_slice_id(cred, urn)
100     if slice_id == None:
101         (ret, output) = call_am_apiclient("GetResourceTopology", ['all', '\"\"'], 5)
102         (ret, output) = call_am_apiclient("GetResourceTopology", ['all', slice_id,], 5)
103     # parse output into rspec XML
104     if output.find("No resouce found") > 0:
105         rspec = "<RSpec type=\"SFA\"> <Fault>No resource found</Fault> </RSpec>"
106     else:
107         comp_rspec = get_xml_by_tag(output, 'computeResource')
108         logger.debug("#### computeResource %s" % comp_rspec)
109         topo_rspec = get_xml_by_tag(output, 'topology')
110         logger.debug("#### topology %s" % topo_rspec)
111         rspec = "<RSpec type=\"SFA\"> <network name=\"" + Config().get_interface_hrn() + "\">";
112         if comp_rspec != None:
113             rspec = rspec + get_xml_by_tag(output, 'computeResource')
114         if topo_rspec != None:
115             rspec = rspec + get_xml_by_tag(output, 'topology')
116         rspec = rspec + "</network> </RSpec>"
117
118     return (rspec)
119
120 def start_slice(api, xrn, cred):
121     # service not supported
122     return None
123
124 def stop_slice(api, xrn, cred):
125     # service not supported
126     return None
127
128 def reset_slices(api, xrn):
129     # service not supported
130     return None
131
132 """
133 Returns the request context required by sfatables. At some point, this mechanism should be changed
134 to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
135 return the basic information needed in a dict.
136 """
137 def fetch_context(slice_hrn, user_hrn, contexts):
138     base_context = {'sfa':{'user':{'hrn':user_hrn}}}
139     return base_context
140     api = SfaAPI()
141     create_slice(api, "plc.maxpl.test000", None, rspec_xml, None)
142