diff --git a/nodepool/status.py b/nodepool/status.py index bb4b1cde9..d7d1d0348 100644 --- a/nodepool/status.py +++ b/nodepool/status.py @@ -142,6 +142,14 @@ def node_list(zk, node_id=None): else: if zk.getNodeLockContenders(node): locked = "locked" + port = node.connection_port + try: + int(port) + except (ValueError, TypeError): + # The port field is being used to carry connection + # information which may contain credentials (e.g., k8s + # service account). Suppress it. + port = "redacted" values = [ node.id, node.provider, @@ -157,7 +165,7 @@ def node_list(zk, node_id=None): node.private_ipv4, node.az, node.username, - node.connection_port, + port, node.launcher, node.allocated_to, node.hold_job, diff --git a/nodepool/tests/unit/test_driver_kubernetes.py b/nodepool/tests/unit/test_driver_kubernetes.py index 5b4919a1a..6170d8e34 100644 --- a/nodepool/tests/unit/test_driver_kubernetes.py +++ b/nodepool/tests/unit/test_driver_kubernetes.py @@ -15,8 +15,10 @@ # limitations under the License. import fixtures +import json import logging import time +from urllib import request from nodepool import tests from nodepool.zk import zookeeper as zk @@ -572,3 +574,40 @@ class TestDriverKubernetes(tests.DBTestCase): servers = manager.listNodes() self.assertEqual(len(servers), 1) + + def test_node_list_k8s_json(self): + # TODO: generalize the k8s test infrastructure (fake client, + # etc) and move this to test_webapp + configfile = self.setup_config('kubernetes.yaml') + pool = self.useNodepool(configfile, watermark_sleep=1) + self.startPool(pool) + webapp = self.useWebApp(pool, port=0) + webapp.start() + port = webapp.server.socket.getsockname()[1] + + req = zk.NodeRequest() + req.state = zk.REQUESTED + req.node_types.append('kubernetes-namespace') + self.zk.storeNodeRequest(req) + + self.log.debug("Waiting for request %s", req.id) + req = self.waitForNodeRequest(req) + self.assertEqual(req.state, zk.FULFILLED) + + req = request.Request( + "http://localhost:%s/node-list" % port) + req.add_header('Accept', 'application/json') + f = request.urlopen(req) + self.assertEqual(f.info().get('Content-Type'), + 'application/json') + data = f.read() + objs = json.loads(data.decode('utf8')) + # We don't check the value of 'locked' because we may get a + # cached value returned. + self.assertDictContainsSubset({'id': '0000000000', + 'ipv6': None, + 'label': ['kubernetes-namespace'], + 'provider': 'kubespray', + 'public_ipv4': None, + 'connection_port': 'redacted', + 'state': 'ready'}, objs[0]) diff --git a/nodepool/tests/unit/test_webapp.py b/nodepool/tests/unit/test_webapp.py index b7aa47f30..1e0b4dc70 100644 --- a/nodepool/tests/unit/test_webapp.py +++ b/nodepool/tests/unit/test_webapp.py @@ -232,6 +232,7 @@ class TestWebApp(tests.DBTestCase): 'label': ['fake-label'], 'provider': 'fake-provider', 'public_ipv4': 'fake', + 'connection_port': 22, 'state': 'ready'}, objs[0]) self.assertTrue('locked' in objs[0]) # specify valid node_id @@ -251,6 +252,7 @@ class TestWebApp(tests.DBTestCase): 'label': ['fake-label'], 'provider': 'fake-provider', 'public_ipv4': 'fake', + 'connection_port': 22, 'state': 'ready'}, objs[0]) self.assertTrue('locked' in objs[0]) # node_id not found