# P1935 UI ## Code Structure * efo * static * network_topology.js 有call到listServices() - request.js listServices() call /api/services * efo * api.py call efo.get_service_status() * efo.py get_service_status(cluster, namespace) call adapter2.py裡的get_service_status Problem * Service function chain: check if only show default cluster? ## Tasks ![](https://i.imgur.com/6LNUQVQ.png) ![](https://i.imgur.com/vvTJO29.png) 1. operator/operator.html字改成Service Topology ![](https://i.imgur.com/kW1kvZm.png) 2. 在api.py裡把list_services()多加registry_svcs ```javacript= # list services (network topology) @bp.route('/services', methods=["GET"]) @login_required def list_services(): svcs, status_code = efo.get_service_status(current_user.id) return make_response(jsonify(svcs), status_code) ``` 3. 在/static/request.js 連結list_appstores, list_branchstores ```javascript= // new function function listStores() { const branch_httpRequest = new XMLHttpRequest(); var branchs = []; branch_httpRequest.onreadystatechange = function() { if (this.readyState === XMLHttpRequest.DONE) { branch_resp = JSON.parse(this.response); for (var i = 0; i < branch_resp.length; i++){ branchs.push(branch_resp[i]["name"]); branchs.push(branch_resp[i]["machine_name"]); branchs.push(branch_resp[i]["cluster_name"]); branchs.push(branch_resp[i]["role"]); branchs.push(branch_resp[i]["ip"]); branchs.push(branch_resp[i]["port"]); branchs.push(branch_resp[i]["image_list"]); branchs.push(branch_resp[i]["total_package_size"]); branchs.push(branch_resp[i]["available_size"]); } } } branch_httpRequest.open('GET', `/api/branchstores`, false); branch_httpRequest.send(); const httpRequest = new XMLHttpRequest(); var apps = []; app_httpRequest.onreadystatechange = function() { if (this.readyState === XMLHttpRequest.DONE) { app_resp = JSON.parse(this.response); for (var i = 0; i < app_resp.length; i++){ apps.push(app_resp[i]["name"]); apps.push(app_resp[i]["machine_name"]); apps.push(app_resp[i]["cluster_name"]); apps.push(app_resp[i]["role"]); apps.push(app_resp[i]["ip"]); apps.push(app_resp[i]["port"]); apps.push(app_resp[i]["image_list"]); apps.push(app_resp[i]["total_package_size"]); apps.push(app_resp[i]["available_size"]); } } } httpRequest.open('GET', `/api/appstores`, false); httpRequest.send(); const merge = [...httpRequest.response, ...branch_httpRequest.response] if ( branch_httpRequest.status === 200 && httpRequest.status === 200){ return merge; /* return: [{ 'name': , 'machine_name': , 'cluster_name': , 'role:' , 'image_list': , 'total_package_size': , 'available_size': }, {}] */ } } ``` 4. 在draw_network_topology(): * 確保其他有用到listServices()的都有改到 * services -> app_svcs * add registry_svcs ```javascript= function draw_network_topology(){ response = listServices(); var services = JSON.parse(response); store_response = listStores(); var nodes = []; var edges = []; prefixes = []; var branchs = []; for ( var i = 0; i < services.length; i++){ // check ip prefix prefix = services[i].ip.split('.')[0]; if (!( prefixes.includes(prefix) )){ prefixes.push(prefix); nodes.push({ id: prefix+".", label: prefix+".", image: "https://i.ibb.co/WB3M1Cc/Edgemaster.png", shape: "image" }); } // add service to topology nodes.push({ id: services[i].ip, label: services[i].ip, image: "https://i.ibb.co/zszT32D/node.png", shape: "image" }); edges.push({ from: prefix+".", to: services[i].ip }); } for ( i = 0 ; i < store_response.length ; i++){ prefix = services[i].ip.split('.')[0]; if ( store_response[i] == branch_resp[i] ) { branchs.push({ id: store_response[i].ip, label: store_response[i].ip, image: "https://i.ibb.co/9WCtqkd/branch.png", shape: "image" }); edges.push({ from: prefix+".", to: store_response[i].ip }); } } var data = { nodes: nodes, edges: edges, branchs: branchs, }; var options = {}; var container = document.querySelector('.network'); network = new vis.Network(container, data, options); network.on('click',(obj)=>{ document.querySelector('.report').innerHTML = obj.nodes[0]; selectnode=obj.nodes[0]; var list="" var listbranch="" for(i = 0; i < services.length; i++){ if(selectnode==services[i].ip){ list=services[i]; break; }else{ list="" } } for(i = 0; i < store_response.length; i++){ if(selectnode==store_response[i].ip){ listbranch=store_response[i]; break; }else{ listbranch="" } } const manis = getManifest(list.name); console.log(manis); list.description = ""; manis.forEach(mani => { data = JSON.parse(mani.data); if ("annotations" in data.metadata) { list.description = data.metadata.annotations.description; } }) const manis_b = getManifest(listbranch.name); console.log(manis_b); listbranch.description = ""; manis_b.forEach(mani => { data = JSON.parse(mani.data); if ("annotations" in data.metadata) { listbranch.description = data.metadata.annotations.description; } }) if (list==services[i]){ var content='<img src="https://i.ibb.co/zszT32D/node.png" width="100">' content+=['<center><table class=topo_table>', '<tr>', '<td colspan="2" height="60"><span style="border-bottom: 2px #6C6C6C solid;font-size: x-large;">'+list.name+'</td>', '</tr>', '<tr>', '<td>IP</td>', '<td>'+list.ip+'</td>', '</tr>', '<tr>', '<td>port</td>', '<td>'+list.port+'</td>', '</tr>', '<tr>', '<td colspan="2" height="50"><span style="border-bottom: 2px #6C6C6C solid;">description</td>', '</tr>', '<tr>', '<td colspan="2">'+list.description+'</td>', '</tr>' ].join("\n"); }else{ var content = ""; } if (listbranch==store_response[i]){ var content='<img src="https://i.ibb.co/9WCtqkd/branch.png" width="100">' content+=['<center><table class=topo_table>', '<tr>', '<td colspan="2" height="60"><span style="border-bottom: 2px #6C6C6C solid;font-size: x-large;">'+list.name+'</td>', '</tr>', '<tr>', '<td>IP</td>', '<td>'+listbranch.ip+'</td>', '</tr>', '<tr>', '<td>port</td>', '<td>'+listbranch.port+'</td>', '</tr>', '<tr>', '<td colspan="2" height="50"><span style="border-bottom: 2px #6C6C6C solid;">description</td>', '</tr>', '<tr>', '<td colspan="2">'+listbranch.description+'</td>', '</tr>', '<button onclick="showpopup();" class=learn_more>more</button>' ].join("\n"); }else{ var content = ""; } document.querySelector('.report').innerHTML = content; document.querySelector('.branch_name').innerHTML = listbranch.name; document.querySelector('.branch_ip').innerHTML = listbranch.ip; document.querySelector('.branch_port').innerHTML = listbranch.port; document.querySelector('.branch_image_list').innerHTML = listbranch.image_list; document.querySelector('.branch_total').innerHTML = listbranch.total_package_size; document.querySelector('.branch_available').innerHTML = listbranch.available_size; }); } ```` * 參考node_topology.js 5. operator/simple.html ```javacript= <div class="report"></div> <div id=popup_box class=popup_box> <a onclick="closepopup();" class="popup_close" href="#">x</a> <h1 style="border-bottom:1px solid lightgray;display: flex;align-items: flex-end;margin-left: 10px;">Owner Node</h1> <div class="node_content"> <img src="https://i.ibb.co/9WCtqkd/branch.png" width="250"> <center><div class="node_name"></div></center> </div> <div class="node_list"> <table class="node_table" text-align="center"> <h2>Basic Information :</h2> <tr> <td>IP</td> <td><div class="branch_ip"></div></td> </tr> <tr> <td>Port</td> <td><div class="branch_port"></div></td> </tr> <tr> <td>Image list</td> <td><div class="branch_image_list"></div></td> </tr> <tr> <td>Total package size</td> <td><div class="branch_total"></div></td> </tr> <tr> <td>Available size</td> <td><div class="branch_available"></div></td> </tr> </table> </div> </div> </div> ``` 6. UI介面 * description部分印出private registry: role e.g. private registry: branchstore * Branchstore/Appstore圖示用不同顏色 * 加more botton * Basic Information: 表格: * ip * port * image_list * total_package_size * available_size # Git操作 * 複製到自己的directory 複製到自己的/home/sherrylee git clone https://github.com/dingyiyi0226/standard-p1935.git * 若要用branch: 開branch並切到branch: git checkout -b sherrylee 每次改時確認一下是否在branch: git status * 有人更新: git pull * 改完想要push到github git config --global user.name "xxxxx" git config --global user.email xxxxx@example.com git add . git commit -m "xxxxx" 到branch: git push origin sherrylee 到master: git push origin master