Merge "Make Info.endpoint a config override"
diff --git a/doc/source/admin/components.rst b/doc/source/admin/components.rst
index 84ebc10..b555abc 100644
--- a/doc/source/admin/components.rst
+++ b/doc/source/admin/components.rst
@@ -618,9 +618,13 @@
Web Server
----------
-The Zuul web server currently acts as a websocket interface to live log
-streaming. Eventually, it will serve as the single process handling all
-HTTP interactions with Zuul.
+.. TODO: Turn REST API into a link to swagger docs when we grow them
+
+The Zuul web server serves as the single process handling all HTTP
+interactions with Zuul. This includes the websocket interface for live
+log streaming, the REST API and the html/javascript dashboard. All three are
+served as a holistic web application. For information on additional supported
+deployment schemes, see :ref:`web-deployment-options`.
Web servers need to be able to connect to the Gearman server (usually
the scheduler host). If the SQL reporter is used, they need to be
@@ -655,6 +659,11 @@
Port to use for web server process.
+ .. attr:: rest_api_url
+
+ Base URL on which the zuul-web REST service is exposed, if different
+ than the base URL where the web application is hosted.
+
.. attr:: websocket_url
Base URL on which the websocket service is exposed, if different
diff --git a/doc/source/admin/installation.rst b/doc/source/admin/installation.rst
index ae7d571..735b315 100644
--- a/doc/source/admin/installation.rst
+++ b/doc/source/admin/installation.rst
@@ -67,3 +67,57 @@
the correct version will be installed automatically with Zuul.
Because of the close integration of Zuul and Ansible, attempting to
use other versions of Ansible with Zuul is not recommended.
+
+.. _web-deployment-options:
+
+Web Deployment Options
+======================
+
+The ``zuul-web`` service provides an web dashboard, a REST API and a websocket
+log streaming service as a single holistic web application. For production use
+it is recommended to run it behind a reverse proxy, such as Apache or Nginx.
+
+More advanced users may desire to do one or more exciting things such as:
+
+White Label
+ Serve the dashboard of an individual tenant at the root of its own domain.
+ https://zuul.openstack.org is an example of a Zuul dashboard that has been
+ white labeled for the ``openstack`` tenant of its Zuul.
+
+Static Offload
+ Shift the duties of serving static files, such as HTML, Javascript, CSS or
+ images either to the Reverse Proxy server or to a completely separate
+ location such as a Swift Object Store or a CDN-enabled static web server.
+
+Sub-URL
+ Serve a Zuul dashboard from a location below the root URL as part of
+ presenting integration with other application.
+ https://softwarefactory-project.io/zuul3/ is an example of a Zuul dashboard
+ that is being served from a Sub-URL.
+
+None of those make any sense for simple non-production oriented deployments, so
+all discussion will assume that the ``zuul-web`` service is exposed via a
+Reverse Proxy. Where rewrite rule examples are given, they will be given
+with Apache syntax, but any other Reverse Proxy should work just fine.
+
+Basic Reverse Proxy
+-------------------
+
+Using Apache as the Reverse Proxy requires the ``mod_proxy``,
+``mod_proxy_http`` and ``mod_proxy_wstunnel`` modules to be installed and
+enabled. Static Offload and White Label additionally require ``mod_rewrite``.
+
+Static Offload
+--------------
+
+.. TODO: Fill in specifics in the next patch
+
+White Labeled Tenant
+--------------------
+
+.. TODO: Fill in specifics in the next patch
+
+Sub-URL
+-------
+
+.. TODO: Fill in specifics in the next patch
diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py
index 602209f..75cf8f3 100644
--- a/tests/unit/test_web.py
+++ b/tests/unit/test_web.py
@@ -254,7 +254,7 @@
self.assertEqual(
info, {
"info": {
- "endpoint": "http://localhost:%s" % self.port,
+ "rest_api_url": None,
"capabilities": {
"job_history": False
},
@@ -275,7 +275,7 @@
self.assertEqual(
info, {
"info": {
- "endpoint": "http://localhost:%s" % self.port,
+ "rest_api_url": None,
"tenant": "tenant-one",
"capabilities": {
"job_history": False
diff --git a/zuul/model.py b/zuul/model.py
index 44e8d06..a434834 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -3214,16 +3214,16 @@
class WebInfo(object):
"""Information about the system needed by zuul-web /info."""
- def __init__(self, websocket_url=None, endpoint=None,
+ def __init__(self, websocket_url=None, rest_api_url=None,
capabilities=None, stats_url=None,
stats_prefix=None, stats_type=None):
self.capabilities = capabilities or Capabilities()
- self.websocket_url = websocket_url
- self.stats_url = stats_url
+ self.rest_api_url = rest_api_url
self.stats_prefix = stats_prefix
self.stats_type = stats_type
- self.endpoint = endpoint
+ self.stats_url = stats_url
self.tenant = None
+ self.websocket_url = websocket_url
def __repr__(self):
return '<WebInfo 0x%x capabilities=%s>' % (
@@ -3231,32 +3231,33 @@
def copy(self):
return WebInfo(
- websocket_url=self.websocket_url,
- endpoint=self.endpoint,
- stats_url=self.stats_url,
+ capabilities=self.capabilities.copy(),
+ rest_api_url=self.rest_api_url,
stats_prefix=self.stats_prefix,
stats_type=self.stats_type,
- capabilities=self.capabilities.copy())
+ stats_url=self.stats_url,
+ websocket_url=self.websocket_url)
@staticmethod
def fromConfig(config):
return WebInfo(
- websocket_url=get_default(config, 'web', 'websocket_url', None),
- stats_url=get_default(config, 'web', 'stats_url', None),
+ rest_api_url=get_default(config, 'web', 'rest_api_url', None),
stats_prefix=get_default(config, 'statsd', 'prefix'),
stats_type=get_default(config, 'web', 'stats_type', 'graphite'),
+ stats_url=get_default(config, 'web', 'stats_url', None),
+ websocket_url=get_default(config, 'web', 'websocket_url', None),
)
def toDict(self):
d = dict()
+ d['capabilities'] = self.capabilities.toDict()
+ d['rest_api_url'] = self.rest_api_url
d['websocket_url'] = self.websocket_url
stats = dict()
- stats['url'] = self.stats_url
stats['prefix'] = self.stats_prefix
stats['type'] = self.stats_type
+ stats['url'] = self.stats_url
d['stats'] = stats
- d['endpoint'] = self.endpoint
- d['capabilities'] = self.capabilities.toDict()
if self.tenant:
d['tenant'] = self.tenant
return d
diff --git a/zuul/web/__init__.py b/zuul/web/__init__.py
index 31eac7d..8f4bf72 100755
--- a/zuul/web/__init__.py
+++ b/zuul/web/__init__.py
@@ -261,19 +261,12 @@
return await self.log_streaming_handler.processRequest(
request)
- async def _handleRootInfo(self, request):
- info = self.info.copy()
- info.endpoint = str(request.url.parent)
- return self._handleInfo(info)
+ def _handleRootInfo(self, request):
+ return self._handleInfo(self.info)
def _handleTenantInfo(self, request):
info = self.info.copy()
info.tenant = request.match_info["tenant"]
- # yarl.URL.parent on a root url returns the root url, so this is
- # both safe and accurate for white-labeled tenants like OpenStack,
- # zuul-web running on / and zuul-web running on a sub-url like
- # softwarefactory-project.io
- info.endpoint = str(request.url.parent.parent.parent)
return self._handleInfo(info)
def _handleInfo(self, info):