web: make console-stream tenant scoped

This change replaces /console-stream route by /{tenant}/console-stream.

Change-Id: Ib5ecbaf2e8a115bb1edebe71696c565b72e7c481
Co-Authored-By: Tobias Henkel <tobias.henkel@bmw.de>
diff --git a/tests/unit/test_log_streamer.py b/tests/unit/test_log_streamer.py
index c808540..27368e3 100644
--- a/tests/unit/test_log_streamer.py
+++ b/tests/unit/test_log_streamer.py
@@ -158,7 +158,7 @@
 
     def runWSClient(self, build_uuid, event):
         async def client(loop, build_uuid, event):
-            uri = 'http://[::1]:9000/console-stream'
+            uri = 'http://[::1]:9000/tenant-one/console-stream'
             try:
                 session = aiohttp.ClientSession(loop=loop)
                 async with session.ws_connect(uri) as ws:
diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py
index cad557e..aacc81e 100755
--- a/tests/unit/test_scheduler.py
+++ b/tests/unit/test_scheduler.py
@@ -2581,7 +2581,7 @@
         self.assertEqual('project-merge', status_jobs[0]['name'])
         # TODO(mordred) pull uuids from self.builds
         self.assertEqual(
-            'static/stream.html?uuid={uuid}&logfile=console.log'.format(
+            'stream.html?uuid={uuid}&logfile=console.log'.format(
                 uuid=status_jobs[0]['uuid']),
             status_jobs[0]['url'])
         self.assertEqual(
@@ -2597,7 +2597,7 @@
             status_jobs[0]['report_url'])
         self.assertEqual('project-test1', status_jobs[1]['name'])
         self.assertEqual(
-            'static/stream.html?uuid={uuid}&logfile=console.log'.format(
+            'stream.html?uuid={uuid}&logfile=console.log'.format(
                 uuid=status_jobs[1]['uuid']),
             status_jobs[1]['url'])
         self.assertEqual(
@@ -2613,7 +2613,7 @@
 
         self.assertEqual('project-test2', status_jobs[2]['name'])
         self.assertEqual(
-            'static/stream.html?uuid={uuid}&logfile=console.log'.format(
+            'stream.html?uuid={uuid}&logfile=console.log'.format(
                 uuid=status_jobs[2]['uuid']),
             status_jobs[2]['url'])
         self.assertEqual(
@@ -4210,7 +4210,7 @@
                 self.assertEqual('gate', job['pipeline'])
                 self.assertEqual(False, job['retry'])
                 self.assertEqual(
-                    'static/stream.html?uuid={uuid}&logfile=console.log'
+                    'stream.html?uuid={uuid}&logfile=console.log'
                     .format(uuid=job['uuid']), job['url'])
                 self.assertEqual(
                     'finger://{hostname}/{uuid}'.format(
diff --git a/zuul/model.py b/zuul/model.py
index e59ccb5..6426bbe 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -1863,7 +1863,7 @@
                 result = build.result
                 finger_url = build.url
                 # TODO(tobiash): add support for custom web root
-                urlformat = 'static/stream.html?' \
+                urlformat = 'stream.html?' \
                             'uuid={build.uuid}&' \
                             'logfile=console.log'
                 if websocket_url:
diff --git a/zuul/web/__init__.py b/zuul/web/__init__.py
index d400f60..8e58081 100755
--- a/zuul/web/__init__.py
+++ b/zuul/web/__init__.py
@@ -340,6 +340,8 @@
             fp = os.path.join(STATIC_DIR, "jobs.html")
         elif request.path.endswith("builds.html"):
             fp = os.path.join(STATIC_DIR, "builds.html")
+        elif request.path.endswith("stream.html"):
+            fp = os.path.join(STATIC_DIR, "stream.html")
         headers = {}
         if self.static_cache_expiry:
             headers['Cache-Control'] = "public, max-age=%d" % \
@@ -358,12 +360,13 @@
             is run within a separate (non-main) thread.
         """
         routes = [
-            ('GET', '/console-stream', self._handleWebsocket),
             ('GET', '/tenants.json', self._handleTenantsRequest),
             ('GET', '/{tenant}/status.json', self._handleStatusRequest),
             ('GET', '/{tenant}/jobs.json', self._handleJobsRequest),
+            ('GET', '/{tenant}/console-stream', self._handleWebsocket),
             ('GET', '/{tenant}/status.html', self._handleStaticRequest),
             ('GET', '/{tenant}/jobs.html', self._handleStaticRequest),
+            ('GET', '/{tenant}/stream.html', self._handleStaticRequest),
             ('GET', '/tenants.html', self._handleStaticRequest),
             ('GET', '/', self._handleStaticRequest),
         ]
diff --git a/zuul/web/static/README b/zuul/web/static/README
index f17ea5f..e924dc7 100644
--- a/zuul/web/static/README
+++ b/zuul/web/static/README
@@ -50,8 +50,7 @@
   </Directory>
 
   # Console-stream needs a special proxy-pass for websocket
-  ProxyPass /console-stream ws://localhost:9000/console-stream nocanon retry=0
-  ProxyPassReverse /console-stream ws://localhost:9000/console-stream
+  ProxyPassMatch /(.*)/console-stream ws://localhost:9000/$1/console-stream nocanon retry=0
 
   # Then only the json calls are sent to the zuul-web endpoints
   ProxyPassMatch ^/(.*.json)$ http://localhost:9000/$1 nocanon retry=0
diff --git a/zuul/web/static/stream.html b/zuul/web/static/stream.html
index dbeb66b..f2e7081 100644
--- a/zuul/web/static/stream.html
+++ b/zuul/web/static/stream.html
@@ -73,7 +73,7 @@
               } else {
                   protocol = 'ws://';
               }
-              path = url['pathname'].replace(/static\/.*$/g, '') + 'console-stream';
+              path = url['pathname'].replace(/stream.html.*$/g, '') + 'console-stream';
               params['websocket_url'] = protocol + url['host'] + path;
           }
           var ws = new WebSocket(params['websocket_url']);