diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py index 2026a24d5c..30eba3b592 100755 --- a/tests/unit/test_web.py +++ b/tests/unit/test_web.py @@ -247,6 +247,18 @@ class TestWeb(BaseTestWeb): self.assertEqual(3, data[0]['projects']) self.assertEqual(1, data[0]['queue']) + def test_web_connections_list(self): + data = self.get_url('api/connections').json() + connection = { + 'driver': 'gerrit', + 'name': 'gerrit', + 'baseurl': 'https://review.example.com', + 'canonical_hostname': 'review.example.com', + 'server': 'review.example.com', + 'port': 29418, + } + self.assertEqual([connection], data) + def test_web_bad_url(self): # do we redirect to index.html resp = self.get_url("status/foo") diff --git a/zuul/connection/__init__.py b/zuul/connection/__init__.py index 0012848bfa..ff0807dac9 100644 --- a/zuul/connection/__init__.py +++ b/zuul/connection/__init__.py @@ -108,3 +108,11 @@ class BaseConnection(object, metaclass=abc.ABCMeta): Registry of all configured connections. """ return False + + def toDict(self): + """Return public information about the connection + """ + return { + "name": self.connection_name, + "driver": self.driver.name, + } diff --git a/zuul/driver/gerrit/gerritconnection.py b/zuul/driver/gerrit/gerritconnection.py index 79522ea71a..f788fda21b 100644 --- a/zuul/driver/gerrit/gerritconnection.py +++ b/zuul/driver/gerrit/gerritconnection.py @@ -353,6 +353,16 @@ class GerritConnection(BaseConnection): self.auth = authclass( self.user, self.password) + def toDict(self): + d = super().toDict() + d.update({ + "baseurl": self.baseurl, + "canonical_hostname": self.canonical_hostname, + "server": self.server, + "port": self.port, + }) + return d + def url(self, path): return self.baseurl + '/a/' + path diff --git a/zuul/driver/git/gitconnection.py b/zuul/driver/git/gitconnection.py index f6e605a814..b5beb6677d 100644 --- a/zuul/driver/git/gitconnection.py +++ b/zuul/driver/git/gitconnection.py @@ -155,6 +155,14 @@ class GitConnection(BaseConnection): self.projects_refs = {} self._change_cache = {} + def toDict(self): + d = super().toDict() + d.update({ + "baseurl": self.baseurl, + "canonical_hostname": self.canonical_hostname, + }) + return d + def getProject(self, name): return self.projects.get(name) diff --git a/zuul/driver/github/githubconnection.py b/zuul/driver/github/githubconnection.py index ada790247b..f4d215aa10 100644 --- a/zuul/driver/github/githubconnection.py +++ b/zuul/driver/github/githubconnection.py @@ -598,6 +598,15 @@ class GithubConnection(BaseConnection): r"^Depends-On: https://%s/.+/.+/pull/[0-9]+$" % self.server, re.MULTILINE | re.IGNORECASE) + def toDict(self): + d = super().toDict() + d.update({ + "baseurl": self.baseurl, + "canonical_hostname": self.canonical_hostname, + "server": self.server, + }) + return d + def onLoad(self): self.log.info('Starting GitHub connection: %s' % self.connection_name) self.gearman_worker = GithubGearmanWorker(self) diff --git a/zuul/rpclistener.py b/zuul/rpclistener.py index de074360d7..7b9dd9b04c 100644 --- a/zuul/rpclistener.py +++ b/zuul/rpclistener.py @@ -78,6 +78,7 @@ class RPCListener(object): self.worker.registerFunction("zuul:pipeline_list") self.worker.registerFunction("zuul:key_get") self.worker.registerFunction("zuul:config_errors_list") + self.worker.registerFunction("zuul:connection_list") def stop(self): self.log.debug("Stopping") @@ -485,3 +486,9 @@ class RPCListener(object): 'source_context': err.key.context.toDict(), 'error': err.error}) job.sendWorkComplete(json.dumps(output)) + + def handle_connection_list(self, job): + output = [] + for source in self.sched.connections.getSources(): + output.append(source.connection.toDict()) + job.sendWorkComplete(json.dumps(output)) diff --git a/zuul/web/__init__.py b/zuul/web/__init__.py index cd5860385f..085e9915ef 100755 --- a/zuul/web/__init__.py +++ b/zuul/web/__init__.py @@ -238,6 +238,15 @@ class ZuulWebAPI(object): resp.headers['Access-Control-Allow-Origin'] = '*' return ret + @cherrypy.expose + @cherrypy.tools.json_out(content_type='application/json; charset=utf-8') + def connections(self): + job = self.rpc.submitJob('zuul:connection_list', {}) + ret = json.loads(job.data[0]) + resp = cherrypy.response + resp.headers['Access-Control-Allow-Origin'] = '*' + return ret + def _getStatus(self, tenant): with self.status_lock: if tenant not in self.cache or \ @@ -680,6 +689,8 @@ class ZuulWeb(object): api = ZuulWebAPI(self) route_map.connect('api', '/api/info', controller=api, action='info') + route_map.connect('api', '/api/connections', + controller=api, action='connections') route_map.connect('api', '/api/tenants', controller=api, action='tenants') route_map.connect('api', '/api/tenant/{tenant}/info',