Chore: Add gerrit maven verify GHA workflow
[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     SDNRHOST=getEnv('SDNRHOST')
281     SDNRPORT=getEnv('SDNRPORT')
282     SDNRWEBSOCKETPORT=getEnv('SDNRWEBSOCKETPORT',SDNRPORT)
283     DNS_RESOLVER=getEnv('DNS_RESOLVER')
284     DNS_INTERNAL_RESOLVER=getEnv('DNS_INTERNAL_RESOLVER')
285     if FN is None:
286         print("unknown env WEBPROTOCOL: {}".format(WEBPROTOCOL))
287         exit(1)
288     
289     # replace needed base parameters
290     sedInFile('WEBPORT',WEBPORT,FN)
291
292     FN='/opt/bitnami/nginx/conf/server_blocks/location.rules'
293     # replace needed parameters in forwarding rules
294     sedInFile('WEBPORT',WEBPORT,FN)
295     sedInFile('SDNRPROTOCOL',SDNRPROTOCOL,FN)
296     sedInFile('SDNRHOST',SDNRHOST ,FN)
297     sedInFile('SDNRPORT',SDNRPORT,FN)
298     sedInFile('SDNRWEBSOCKETPORT',SDNRWEBSOCKETPORT, FN)
299     sedInFile('DNS_RESOLVER',DNS_RESOLVER ,FN)
300     sedInFile('DNS_INTERNAL_RESOLVER',DNS_INTERNAL_RESOLVER ,FN)
301
302     TRPCEURL=getEnv('TRPCEURL')
303     TOPOURL=getEnv('TOPOURL')
304     SITEDOCURL=getEnv('SITEDOCURL')
305     TILEURL=getEnv('TILEURL')
306     DATAPROVIDERURL=getEnv('DATAPROVIDERURL')
307     TERRAINURL=getEnv('TERRAINURL')
308     # handle optional parameters
309     if TRPCEURL is None:
310         print("transportPCE forwarding disabled")
311         sedInFile('proxy_pass TRPCEURL/$1;','return 404;',FN)
312     else:
313         sedInFile('TRPCEURL',TRPCEURL ,FN)
314
315     if TOPOURL is None:
316         print("topology api forwarding disabled")
317         sedInFile('proxy_pass TOPOURL;','return 404;',FN)
318     else:
319         sedInFile('TOPOURL',TOPOURL ,FN)
320     
321     if SITEDOCURL is None:
322         print("sitedoc api forwarding disabled")
323         sedInFile('proxy_pass SITEDOCURL/topology/stadok/$1;','return 404;', FN)
324     else:
325         sedInFile('SITEDOCURL',SITEDOCURL, FN)
326     
327     if TILEURL is None:
328         print("tile server forwarding disabled")
329         sedInFile('proxy_pass TILEURL/$1;','return 404;',FN)
330     else:
331         sedInFile('TILEURL',TILEURL ,FN)
332     
333     if DATAPROVIDERURL is None:
334         print("data provider forwarding disabled")
335         sedInFile('proxy_pass DATAPROVIDERURL/$1;','return 404;',FN)
336     else:
337         sedInFile('DATAPROVIDERURL',DATAPROVIDERURL ,FN)
338     
339     if TERRAINURL is None:
340         print("terrain server forwarding disabled")
341         sedInFile('proxy_pass TERRAINURL/$1;','return 404;',FN)
342     else:
343         sedInFile('TERRAINURL',TERRAINURL ,FN)