fix sdnr ws port configs
[sdnc/oam.git] / installation / sdnc-web / src / main / scripts / core.py
1 ###
2 # ============LICENSE_START=======================================================
3 # ONAP : ccsdk distribution web
4 # ================================================================================
5 # Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
6 # All rights reserved.
7 # ================================================================================
8 # Licensed under the Apache License, Version 2.0 (the "License");
9 # you may not use this file except in compliance with the License.
10 # You may obtain a copy of the License at
11 #
12 #      http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS,
16 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 # See the License for the specific language governing permissions and
18 # limitations under the License.
19 # ============LICENSE_END=========================================================
20 ###
21 import subprocess
22 import os
23 import json
24 import zipfile
25 import re
26 import uuid
27 import urllib3
28 import shutil
29 import re
30 import ssl
31 urllib3.disable_warnings()
32
33 APPLICATION_LISTFILE="/app/odlux.application.list"
34 INIT_FOLDER="/app/init.d"
35 ODLUX_BASE_FOLDER='/app/odlux'
36 INDEX_HTML=ODLUX_BASE_FOLDER+'/index.html'
37 INDEX_HTML_TEMPLATE=INDEX_HTML+'.template'
38 DEFAULT_APPLICATIONS=["connectApp" "faultApp" "maintenanceApp" "configurationApp" "performanceHistoryApp" "inventoryApp" "eventLogApp" "mediatorApp" "helpApp"]
39 http = urllib3.PoolManager(cert_reqs=ssl.CERT_NONE)
40     
41 def exec(command):
42     output = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout.read()
43     return output
44 def execToStdOut(commandArray):
45     process = subprocess.Popen(commandArray, shell=False)
46     process.communicate()
47
48 def download(url, dst):
49     print("downloading from {}...".format(url),end="")
50     with open(dst, 'wb') as out_file:
51         resp= http.request('GET',url, preload_content=False)
52         shutil.copyfileobj(resp, out_file)
53         resp.release_conn() 
54     print("done")
55
56 def getEnv(key, defaultValue=None):
57     x=os.getenv(key)
58     return x if x is not None and len(x)>0 else defaultValue
59
60 def sedInFile(old, nu, fn):
61     execToStdOut(['sed', '-i', 's|{}|{}|g'.format(old,nu),fn])
62
63 def add_application(name, index, file=None):
64     apps = load_applications()
65     if index==0:
66         print("no index given. put it to last position")
67         index=apps[len(apps)-1]['index']+10
68     apps.append(dict(index=index,name=name))
69     if file is not None and os.path.exists(file):
70         extract(file)
71     else:
72         print('unable to find file {}'.format(file))
73     write_applications(apps)
74     print("{} installed on index {}".format(name, index)) 
75
76 def initial_load():
77     files = os.listdir(INIT_FOLDER)
78     regex = r"([0-9]+)([a-zA-Z]+)\.(jar|zip)"
79     regexUrl = r"([0-9]+)([a-zA-Z]+)\.(url)"
80     for file in files:
81         matches = re.finditer(regex,file)
82         match = next(matches, None)
83         matchesUrl = re.finditer(regexUrl,file)
84         matchUrl = next(matchesUrl, None)
85         if match is not None:
86             print("installing {}".format(file))
87             index = int(match.group(1))
88             name = match.group(2)
89             add_application(name,index,INIT_FOLDER+'/'+file)
90         elif matchUrl is not None:
91             print("installing {}".format(file))
92             index = int(match.group(1))
93             name = match.group(2)
94             add_application(name,index,INIT_FOLDER+'/'+file)
95         else:
96             print("no index naming format found. try to autodetect")
97             infos = autoDetectInfosFromJar(file)
98             if infos is None:
99                 print("unable to detect index and application name for {}".format(file))
100             else:
101                add_application(infos['name'],infos['index'],INIT_FOLDER+'/'+file) 
102
103
104
105 def containsBlueprintExpression(file) -> bool:
106     print("check if file {} is blueprint".format(file))
107     with open(file, 'r') as fp:
108         lines = fp.readlines()
109         for line in lines:
110             if "<blueprint" in line:
111                 return True
112         fp.close()
113     return False
114
115 def findBlueprintXml(dir):
116     result = [os.path.join(dp, f) for dp, dn, filenames in os.walk(dir) for f in filenames if os.path.splitext(f)[1] == '.xml']
117     for file in result:
118         if containsBlueprintExpression(file):
119             return file
120     return None
121
122 def autoDetectInfosFromJar(file):
123     print("autodetect infos(appName and index) from jar {}".format(file))
124     tmpDir=getRandomTempDir()
125     regexBundleName = r"<property[\ ]+name=\"bundleName\"[\ ]+value=\"([^\"]+)\""
126     regexIndex = r"<property[\ ]+name=\"index\"[\ ]+value=\"([^\"]+)\""
127     name=None
128     index=0
129     with zipfile.ZipFile(file, 'r') as zip_ref:
130         zip_ref.extractall(tmpDir)
131         blueprint = findBlueprintXml(tmpDir)
132         if blueprint is None:
133             return None
134         with open(blueprint) as fp:
135             lines = fp.readlines()
136             for line in lines:
137                 if name is None:
138                     matches = re.finditer(regexBundleName, line)
139                     match = next(matches,None)
140                     if match is not None:
141                         name = match.group(1)
142                 if index == 0:
143                     matches = re.finditer(regexIndex, line)
144                     match = next(matches,None)
145                     if match is not None:
146                         index = int(match.group(1))
147        
148             fp.close()
149     print("found infos from jar: name={} index={}".format(name,index))
150     return dict(index=index,name=name)
151         
152 def getRandomTempDir(create=False):
153     while(True):
154         dir='/tmp/{}'.format(uuid.uuid4())
155         if not os.path.exists(dir):
156 #            print("found random not-existing dir {}".format(dir))
157             if create:
158                 os.makedirs(dir)
159             return dir
160 #        print("dir {} already exists. try new".format(dir))
161     return None
162
163 def getRandomTempFile():
164     dir = getRandomTempDir(True)
165     if dir is None:
166         return None
167
168     while True:
169         file='{}/{}.dat'.format(dir,uuid.uuid4())
170         if not os.path.exists(file):
171 #            print("found random not-existing file {}".format(file))
172             return file
173 #        print("file {} already exists. try new".format(file))
174     return None
175
176 def extract(fn):
177
178     tmpDir=getRandomTempDir()  
179     with zipfile.ZipFile(fn, 'r') as zip_ref:
180         zip_ref.extractall(tmpDir)
181         exec(" ".join(['cp','-r',tmpDir+'/odlux/*',ODLUX_BASE_FOLDER+'/']))
182         zip_ref.close()
183
184
185 def load_applications():
186     apps=[]
187     if os.path.exists(APPLICATION_LISTFILE):
188         with open(APPLICATION_LISTFILE,'r') as fp:
189             lines= fp.readlines()
190             for line in lines:
191                 if len(line.rstrip())<=0:
192                     continue
193                 try:
194                     hlp=line.split(' ')
195                     apps.append(dict(index=int(hlp[0]),name=hlp[1].rstrip()))
196                 except:
197                     print('problem reading line {}'.format(line))
198             fp.close()
199     else:
200         index=10
201         for app in DEFAULT_APPLICATIONS:
202             apps.append(dict(index=index,name=app))
203             index+=10
204 #    print('applications loaded={}'.format(apps))
205     return sorted(apps, key=lambda d: d['index']) 
206   
207 def write_applications(apps):
208 #    print('saving applications={}'.format(apps))
209     apps = sorted(apps, key=lambda d: d['index'])
210     os.remove(APPLICATION_LISTFILE)
211     with open(APPLICATION_LISTFILE,'w') as fp:
212         for app in apps:
213             fp.write('{} {}\n'.format(app['index'], app['name']))
214         fp.close()
215
216 def update_index_html(apps=None):
217  
218 #     # Backup the index.html file
219     if not os.path.exists(INDEX_HTML_TEMPLATE):
220         execToStdOut(['cp',INDEX_HTML,INDEX_HTML_TEMPLATE])
221     else:
222         execToStdOut(['cp',INDEX_HTML_TEMPLATE,INDEX_HTML])
223 #     #default values
224     if apps is None:
225         apps=load_applications()
226     ODLUX_AUTH_METHOD="basic"
227     ENABLE_ODLUX_RBAC=getEnv('ENABLE_ODLUX_RBAC','false')
228     TRPCEGUIURL=getEnv('TRPCEGUIURL')
229
230     if getEnv('ENABLE_OAUTH') == "true":
231         ODLUX_AUTH_METHOD="oauth"
232     ODLUX_CONFIG=dict(authentication=ODLUX_AUTH_METHOD,enablePolicy=ENABLE_ODLUX_RBAC == 'true')
233     print("authentication is {}".format(ODLUX_AUTH_METHOD))
234     print("rbac access is enabled: {}".format(ENABLE_ODLUX_RBAC))
235    
236     if TRPCEGUIURL is not None:
237         ODLUX_CONFIG['transportpceUrl']=TRPCEGUIURL
238         print("trpce gui url is: {}".format(TRPCEGUIURL))
239
240 #    sed -z 's/<script>[^<]*<\/script>/<script>\n    \/\/ run the application \n  require\(\[\"connectApp\",\"faultApp\",\"maintenanceApp\",\"configurationApp\",\"performanceHistoryApp\",\"inventoryApp\",\"eventLogApp\",\"mediatorApp\",\"networkMapApp\",\"linkCalculationApp\",\"helpApp\",\"run\"\], function \(connectApp,faultApp,maintenanceApp,configurationApp,performanceHistoryApp,inventoryApp,eventLogApp,mediatorApp,networkMapApp,linkCalculationApp,helpApp,run\) \{ \n run.configure('$ODLUX_CONFIG'); \n    connectApp.register\(\); \n  faultApp.register\(\);\n    maintenanceApp.register\(\); \n     configurationApp.register\(\);\n    performanceHistoryApp.register\(\); \n    inventoryApp.register\(\);\n    eventLogApp.register\(\);\n   mediatorApp.register\(\);\n   networkMapApp.register\(\);\n   linkCalculationApp.register\(\);\n     helpApp.register\(\);\n      run.runApplication();\n    \}\);\n  <\/script>/' -i /opt/bitnami/nginx/html/odlux/index.html 
241     requireArg=""
242     fnArgs=""
243     appCalls=""
244     for app in apps:
245         requireArg+='"{}",'.format(app['name'])
246         fnArgs+='{},'.format(app['name'])
247         appCalls+='{}.register();\\n'.format(app['name'])
248     #replace require expression
249     execToStdOut(['sed', '-z', 's/require(\["run"\],\ function\ (run)/require\(\[{}\"run\"\], function \({}run\)/'.format(requireArg,fnArgs), '-i', INDEX_HTML]) 
250     #replace run.runApplication expression
251     execToStdOut(['sed','-z', 's/run.runApplication();/{}run.runApplication();/'.format(appCalls), '-i',INDEX_HTML])
252     #replace run.configure expression if exists
253     execToStdOut(['sed', '-z', 's|run.configureApplication([^)]\+)|run.configureApplication({});|'.format(json.dumps(ODLUX_CONFIG)), '-i', INDEX_HTML]) 
254   
255
256 def check_for_rule_template():
257     if os.path.exists('/opt/bitnami/nginx/conf/server_blocks/location.rules.tmpl'):
258         print("using template for forwarding rules")
259         execToStdOut(['cp','/opt/bitnami/nginx/conf/server_blocks/location.rules.tmpl','/opt/bitnami/nginx/conf/server_blocks/location.rules'])
260
261 def update_nginx_site_conf():
262     FN=None
263     if getEnv('WEBPROTOCOL') == "HTTPS":
264         FN='/opt/bitnami/nginx/conf/server_blocks/https_site.conf'
265         execToStdOut(['rm', '/opt/bitnami/nginx/conf/server_blocks/http_site.conf'])
266         SSL_CERT_DIR=getEnv('SSL_CERT_DIR')
267         SSL_CERTIFICATE=getEnv('SSL_CERTIFICATE')
268         SSL_CERTIFICATE_KEY=getEnv('SSL_CERTIFICATE_KEY')
269         sedInFile('SSL_CERTIFICATE_KEY',SSL_CERTIFICATE_KEY,FN)
270         sedInFile('SSL_CERT_DIR',SSL_CERT_DIR,FN)
271         sedInFile('SSL_CERTIFICATE',SSL_CERTIFICATE, FN)
272         
273     elif getEnv('WEBPROTOCOL') == "HTTP":
274         FN='/opt/bitnami/nginx/conf/server_blocks/http_site.conf'
275         execToStdOut(['rm', '/opt/bitnami/nginx/conf/server_blocks/https_site.conf'])
276
277     WEBPROTOCOL=getEnv('WEBPROTOCOL')
278     WEBPORT=getEnv('WEBPORT')
279     SDNRPROTOCOL=getEnv('SDNRPROTOCOL')
280     SDNCWEBHOST=getEnv('HOSTNAME')
281     SDNRHOST=getEnv('SDNRHOST')
282     if SDNRHOST == "sdnc.onap":
283         # Request is from K8s
284         SDNCWEBHOSTINDEX=SDNCWEBHOST[SDNCWEBHOST.rindex("-")+1:]
285         SDNRHOST = "sdnc-" + SDNCWEBHOSTINDEX + ".onap" 
286     SDNRPORT=getEnv('SDNRPORT')
287     SDNRWEBSOCKETPORT=getEnv('SDNRWEBSOCKETPORT',SDNRPORT)
288     DNS_RESOLVER=getEnv('DNS_RESOLVER')
289     DNS_INTERNAL_RESOLVER=getEnv('DNS_INTERNAL_RESOLVER')
290     if FN is None:
291         print("unknown env WEBPROTOCOL: {}".format(WEBPROTOCOL))
292         exit(1)
293     
294     # replace needed base parameters
295     sedInFile('WEBPORT',WEBPORT,FN)
296
297     FN='/opt/bitnami/nginx/conf/server_blocks/location.rules'
298     # replace needed parameters in forwarding rules
299     sedInFile('WEBPORT',WEBPORT,FN)
300     sedInFile('SDNRPROTOCOL',SDNRPROTOCOL,FN)
301     sedInFile('SDNRHOST',SDNRHOST ,FN)
302     sedInFile('SDNRPORT',SDNRPORT,FN)
303     sedInFile('SDNRWEBSOCKETPORT',SDNRWEBSOCKETPORT, FN)
304     sedInFile('DNS_RESOLVER',DNS_RESOLVER ,FN)
305     sedInFile('DNS_INTERNAL_RESOLVER',DNS_INTERNAL_RESOLVER ,FN)
306
307     TRPCEURL=getEnv('TRPCEURL')
308     TOPOURL=getEnv('TOPOURL')
309     SITEDOCURL=getEnv('SITEDOCURL')
310     TILEURL=getEnv('TILEURL')
311     DATAPROVIDERURL=getEnv('DATAPROVIDERURL')
312     TERRAINURL=getEnv('TERRAINURL')
313     # handle optional parameters
314     if TRPCEURL is None:
315         print("transportPCE forwarding disabled")
316         sedInFile('proxy_pass TRPCEURL/$1;','return 404;',FN)
317     else:
318         sedInFile('TRPCEURL',TRPCEURL ,FN)
319
320     if TOPOURL is None:
321         print("topology api forwarding disabled")
322         sedInFile('proxy_pass TOPOURL;','return 404;',FN)
323     else:
324         sedInFile('TOPOURL',TOPOURL ,FN)
325     
326     if SITEDOCURL is None:
327         print("sitedoc api forwarding disabled")
328         sedInFile('proxy_pass SITEDOCURL/topology/stadok/$1;','return 404;', FN)
329     else:
330         sedInFile('SITEDOCURL',SITEDOCURL, FN)
331     
332     if TILEURL is None:
333         print("tile server forwarding disabled")
334         sedInFile('proxy_pass TILEURL/$1;','return 404;',FN)
335     else:
336         sedInFile('TILEURL',TILEURL ,FN)
337     
338     if DATAPROVIDERURL is None:
339         print("data provider forwarding disabled")
340         sedInFile('proxy_pass DATAPROVIDERURL/$1;','return 404;',FN)
341     else:
342         sedInFile('DATAPROVIDERURL',DATAPROVIDERURL ,FN)
343     
344     if TERRAINURL is None:
345         print("terrain server forwarding disabled")
346         sedInFile('proxy_pass TERRAINURL/$1;','return 404;',FN)
347     else:
348         sedInFile('TERRAINURL',TERRAINURL ,FN)