k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/maintenance/oncall.html (about) 1 <!DOCTYPE html> 2 <!-- To "deploy": gsutil cp -Z oncall.html gs://test-infra-oncall/ --> 3 <html lang="en"> 4 <script> 5 var rotationsMetadata = { 6 "google-build-admin": { 7 "prettyName": "Google Build Admin", 8 "slack": "@google-build-admin", 9 "timezone": '<a href="https://time.is/PT">PT</a>', 10 "description": 'Debian / RPM package build & publishing for releases', 11 }, 12 "testinfra": { 13 "prettyName": "Test Infra", 14 "slack": "@test-infra-oncall", 15 "timezone": '<a href="https://time.is/PT">PT</a>', 16 "description": "Prow, TestGrid, and other Google hosted infrastructure" 17 }, 18 "scalability": { 19 "prettyName": "Scalability", 20 "timezone": '<a href="https://time.is/CET">CET</a>', 21 // TODO: description 22 } 23 }; 24 // extracted/modified from kubernetes/test-infra/gubernator/static/build.js 25 function get(uri, callback) { 26 if (uri[0] === '/') { 27 // Matches /bucket/file/path -> [..., "bucket", "file/path"] 28 var groups = uri.match(/([^/:]+)\/(.*)/); 29 var bucket = groups[1], path = groups[2]; 30 var url = 'https://www.googleapis.com/storage/v1/b/' + bucket + '/o/' + 31 encodeURIComponent(path) + '?alt=media'; 32 } else { 33 var url = uri; 34 } 35 var req = new XMLHttpRequest(); 36 req.open('GET', url); 37 req.onload = function (resp) { 38 callback(req); 39 }; 40 req.send(); 41 } 42 43 function build_table(req) { 44 var data = req.response; 45 var oncall = JSON.parse(data).Oncall; 46 var keys = Object.keys(oncall).sort(); 47 48 var html = ''; 49 html += '<table>'; 50 html += '<thead> <tr> <th> Rotation </th> <th> Slack </th> <th colspan=2> Current </th> <th> Time Zone </th> <th> Description </th> </tr>'; 51 html += '<tbody>'; 52 for (var i = 0; i < keys.length; i++) { 53 var key = keys[i]; 54 var person = oncall[key]; 55 // get info about this rotation 56 var rotationInfo = rotationsMetadata[key]; 57 var name = key; 58 var description = ""; 59 var timezone = ""; 60 var slack = ""; 61 if (rotationInfo) { 62 if ("prettyName" in rotationInfo) { 63 name = rotationInfo["prettyName"]; 64 } 65 if ("slack" in rotationInfo) { 66 slack = rotationInfo["slack"]; 67 } 68 if ("description" in rotationInfo) { 69 description = rotationInfo["description"]; 70 } 71 if ("timezone" in rotationInfo) { 72 timezone = rotationInfo["timezone"]; 73 } 74 } 75 // add to table 76 html += '<tr>'; 77 html += '<td style="font-weight: bold">' + name + '</td>'; 78 if (person) { 79 html += '<td><code>' + slack + '</code></td>'; 80 html += '<td> <a href="https://github.com/' + person + '">' + person + ' </td>'; 81 html += '<td> <img src="https://github.com/' + person + '.png?size=125" alt=""></a> </td>'; 82 html += '<td>' + timezone + '</td>'; 83 html += '<td>' + description + '</td>'; 84 } else { 85 html += 'None'; 86 } 87 html += '</tr>' 88 } 89 html += '</tbody>'; 90 html += '</table>'; 91 92 // trivial XSS, but storage.googleapis.com is even more trivial XSS! 93 document.getElementById('oncall').innerHTML = html; 94 95 document.getElementById('updated').innerText = req.getResponseHeader('date'); 96 } 97 98 get('/kubernetes-jenkins/oncall.json', build_table); 99 </script> 100 <title>K8s Oncall Rotations</title> 101 <style> 102 body { 103 background-color: #eee; 104 margin-left: auto; 105 margin-right: auto; 106 text-align: center; 107 } 108 109 img { 110 padding-left: 10px; 111 max-width: 125px; 112 } 113 114 table, th, td { 115 border: 1px solid black; 116 } 117 118 th, td { 119 padding: 5px; 120 text-align: center; 121 } 122 123 #oncall { 124 display: inline-block; 125 } 126 </style> 127 <body> 128 <h1>Kubernetes Oncall Rotations</h1> 129 <p>Updated: <span id="updated">Never</span> 130 <h2>NOTE: Rotations are Google-staffed, volunteer, best-effort during business-hours.</h2> 131 <div id="oncall">Loading...</div> 132 <div><a href="https://storage.googleapis.com/kubernetes-jenkins/oncall.json">data source</a></div> 133 </body> 134 </html>