def kubernetes_create_connection(address, *args, **kwargs): dns_name = address[0] if isinstance(dns_name, bytes): dns_name = dns_name.decode() dns_name = dns_name.split(".") if len(dns_name) != 3 or dns_name[2] != "kubernetes": return socket_create_connection(address, *args, **kwargs) pf = portforward(api.connect_get_namespaced_pod_portforward, dns_name[0], dns_name[1], ports=str(address[1])) return pf.socket(address[1])
def kubernetes_create_connection(address, *args, **kwargs): dns_name = address[0] if isinstance(dns_name, bytes): dns_name = dns_name.decode() dns_name = dns_name.split(".") if dns_name[-1] != 'kubernetes': return socket_create_connection(address, *args, **kwargs) if len(dns_name) not in (3, 4): raise RuntimeError("Unexpected kubernetes DNS name.") namespace = dns_name[-2] name = dns_name[0] port = address[1] if len(dns_name) == 4: if dns_name[1] in ('svc', 'service'): service = api_instance.read_namespaced_service(name, namespace) for service_port in service.spec.ports: if service_port.port == port: port = service_port.target_port break else: raise RuntimeError("Unable to find service port: %s" % port) label_selector = [] for key, value in service.spec.selector.items(): label_selector.append("%s=%s" % (key, value)) pods = api_instance.list_namespaced_pod( namespace, label_selector=",".join(label_selector)) if not pods.items: raise RuntimeError("Unable to find service pods.") name = pods.items[0].metadata.name if isinstance(port, str): for container in pods.items[0].spec.containers: for container_port in container.ports: if container_port.name == port: port = container_port.container_port break else: continue break else: raise RuntimeError( "Unable to find service port name: %s" % port) elif dns_name[1] != 'pod': raise RuntimeError("Unsupported resource type: %s" % dns_name[1]) pf = portforward(api_instance.connect_get_namespaced_pod_portforward, name, namespace, ports=str(port)) return pf.socket(port)
def connect(self): corev1 = client.CoreV1Api(self.api_client) service = corev1.read_namespaced_service(self.service, self.namespace) label_selector = ','.join(k + '=' + v for k, v in service.spec.selector.items()) pods = corev1.list_namespaced_pod( namespace=self.namespace, label_selector=label_selector, ) self.port_forwarder = portforward( corev1.connect_get_namespaced_pod_portforward, pods.items[0].metadata.name, self.namespace, ports=str(self.remote_port), )
def test_portforward_raw(self): client = api_client.ApiClient(configuration=self.config) api = core_v1_api.CoreV1Api(client) with open(os.path.join(os.path.dirname(__file__), 'port_server.py')) as fh: port_server_py = fh.read() name = 'portforward-raw-' + short_uuid() resp = api.create_namespaced_config_map( body={ 'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': { 'name': name, }, 'data': { 'port-server.py': port_server_py, } }, namespace='default', ) resp = api.create_namespaced_pod( body={ 'apiVersion': 'v1', 'kind': 'Pod', 'metadata': { 'name': name }, 'spec': { 'containers': [ { 'name': 'port-server', 'image': 'python', 'command': [ '/opt/port-server.py', '1234', '1235', ], 'volumeMounts': [ { 'name': 'port-server', 'mountPath': '/opt', 'readOnly': True, }, ], 'startupProbe': { 'tcpSocket': { 'port': 1234, }, }, }, ], 'volumes': [ { 'name': 'port-server', 'configMap': { 'name': name, 'defaultMode': 0o777, }, }, ], }, }, namespace='default', ) self.assertEqual(name, resp.metadata.name) self.assertTrue(resp.status.phase) while True: resp = api.read_namespaced_pod(name=name, namespace='default') self.assertEqual(name, resp.metadata.name) self.assertTrue(resp.status.phase) if resp.status.phase != 'Pending': break time.sleep(1) self.assertEqual(resp.status.phase, 'Running') pf = portforward(api.connect_get_namespaced_pod_portforward, name, 'default', ports='1234,1235,1236') self.assertTrue(pf.connected) sock1234 = pf.socket(1234) sock1235 = pf.socket(1235) sock1234.setblocking(True) sock1235.setblocking(True) sent1234 = b'Test port 1234 forwarding...' sent1235 = b'Test port 1235 forwarding...' sock1234.sendall(sent1234) sock1235.sendall(sent1235) reply1234 = b'' reply1235 = b'' while True: rlist = [] if sock1234.fileno() != -1: rlist.append(sock1234) if sock1235.fileno() != -1: rlist.append(sock1235) if not rlist: break r, _w, _x = select.select(rlist, [], [], 1) if not r: break if sock1234 in r: data = sock1234.recv(1024) self.assertNotEqual(data, b'', "Unexpected socket close") reply1234 += data if sock1235 in r: data = sock1235.recv(1024) self.assertNotEqual(data, b'', "Unexpected socket close") reply1235 += data self.assertEqual(reply1234, sent1234) self.assertEqual(reply1235, sent1235) self.assertTrue(pf.connected) sock = pf.socket(1236) self.assertRaises(socket.error, sock.sendall, b'This should fail...') self.assertIsNotNone(pf.error(1236)) sock.close() for sock in (sock1234, sock1235): self.assertTrue(pf.connected) sent = b'Another test using fileno %s' % str( sock.fileno()).encode() sock.sendall(sent) reply = b'' while True: r, _w, _x = select.select([sock], [], [], 1) if not r: break data = sock.recv(1024) self.assertNotEqual(data, b'', "Unexpected socket close") reply += data self.assertEqual(reply, sent) sock.close() time.sleep(1) self.assertFalse(pf.connected) self.assertIsNone(pf.error(1234)) self.assertIsNone(pf.error(1235)) resp = api.delete_namespaced_pod(name=name, namespace='default') resp = api.delete_namespaced_config_map(name=name, namespace='default')
def portforward_commands(api_instance): name = 'portforward-example' resp = None try: resp = api_instance.read_namespaced_pod(name=name, namespace='default') except ApiException as e: if e.status != 404: print("Unknown error: %s" % e) exit(1) if not resp: print("Pod %s does not exist. Creating it..." % name) pod_manifest = { 'apiVersion': 'v1', 'kind': 'Pod', 'metadata': { 'name': name }, 'spec': { 'containers': [{ 'image': 'nginx', 'name': 'nginx', }] } } api_instance.create_namespaced_pod(body=pod_manifest, namespace='default') while True: resp = api_instance.read_namespaced_pod(name=name, namespace='default') if resp.status.phase != 'Pending': break time.sleep(1) print("Done.") pf = portforward( api_instance.connect_get_namespaced_pod_portforward, name, 'default', ports='80', ) http = pf.socket(80) http.setblocking(True) http.sendall(b'GET / HTTP/1.1\r\n') http.sendall(b'Host: 127.0.0.1\r\n') http.sendall(b'Connection: close\r\n') http.sendall(b'Accept: */*\r\n') http.sendall(b'\r\n') response = b'' while True: select.select([http], [], []) data = http.recv(1024) if not data: break response += data http.close() print(response.decode('utf-8')) error = pf.error(80) if error is None: print("No port forward errors on port 80.") else: print("Port 80 has the following error: %s" % error) # Monkey patch socket.create_connection which is used by http.client and # urllib.request. The same can be done with urllib3.util.connection.create_connection # if the "requests" package is used. socket_create_connection = socket.create_connection def kubernetes_create_connection(address, *args, **kwargs): dns_name = address[0] if isinstance(dns_name, bytes): dns_name = dns_name.decode() dns_name = dns_name.split(".") if dns_name[-1] != 'kubernetes': return socket_create_connection(address, *args, **kwargs) if len(dns_name) not in (3, 4): raise RuntimeError("Unexpected kubernetes DNS name.") namespace = dns_name[-2] name = dns_name[0] port = address[1] if len(dns_name) == 4: if dns_name[1] in ('svc', 'service'): service = api_instance.read_namespaced_service(name, namespace) for service_port in service.spec.ports: if service_port.port == port: port = service_port.target_port break else: raise RuntimeError("Unable to find service port: %s" % port) label_selector = [] for key, value in service.spec.selector.items(): label_selector.append("%s=%s" % (key, value)) pods = api_instance.list_namespaced_pod( namespace, label_selector=",".join(label_selector)) if not pods.items: raise RuntimeError("Unable to find service pods.") name = pods.items[0].metadata.name if isinstance(port, str): for container in pods.items[0].spec.containers: for container_port in container.ports: if container_port.name == port: port = container_port.container_port break else: continue break else: raise RuntimeError( "Unable to find service port name: %s" % port) elif dns_name[1] != 'pod': raise RuntimeError("Unsupported resource type: %s" % dns_name[1]) pf = portforward(api_instance.connect_get_namespaced_pod_portforward, name, namespace, ports=str(port)) return pf.socket(port) socket.create_connection = kubernetes_create_connection # Access the nginx http server using the # "<pod-name>.pod.<namespace>.kubernetes" dns name. response = urllib_request.urlopen('http://%s.pod.default.kubernetes' % name) html = response.read().decode('utf-8') response.close() print('Status Code: %s' % response.code) print(html)