mirror of
https://github.com/openziti/zrok.git
synced 2025-02-07 13:59:47 +01:00
add a py sdk example for a proxy backend
This commit is contained in:
parent
141d219ef7
commit
26a3d802e7
153
sdk/python/examples/proxy/proxy.py
Normal file
153
sdk/python/examples/proxy/proxy.py
Normal file
@ -0,0 +1,153 @@
|
||||
import argparse
|
||||
import atexit
|
||||
import logging
|
||||
import sys
|
||||
import urllib.parse
|
||||
|
||||
import requests
|
||||
from flask import Flask, Response, request
|
||||
from waitress import serve
|
||||
from zrok.model import ShareRequest, Share
|
||||
from zrok.overview import EnvironmentAndResources, Overview
|
||||
|
||||
import zrok
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = Flask(__name__)
|
||||
target_url = None
|
||||
zrok_opts = {}
|
||||
bindPort = 18081
|
||||
|
||||
# List of hop-by-hop headers that should not be returned to the viewer
|
||||
HOP_BY_HOP_HEADERS = {
|
||||
'connection',
|
||||
'keep-alive',
|
||||
'proxy-authenticate',
|
||||
'proxy-authorization',
|
||||
'te',
|
||||
'trailers',
|
||||
'transfer-encoding',
|
||||
'upgrade'
|
||||
}
|
||||
|
||||
|
||||
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH'])
|
||||
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH'])
|
||||
def proxy(path):
|
||||
global target_url
|
||||
logger.info(f"Incoming {request.method} request to {request.path}")
|
||||
logger.info(f"Headers: {dict(request.headers)}")
|
||||
|
||||
# Forward the request to target URL
|
||||
full_url = urllib.parse.urljoin(target_url, request.path)
|
||||
logger.info(f"Forwarding to: {full_url}")
|
||||
|
||||
# Copy request headers, excluding hop-by-hop headers
|
||||
headers = {k: v for k, v in request.headers.items() if k.lower() not in HOP_BY_HOP_HEADERS and k.lower() != 'host'}
|
||||
|
||||
try:
|
||||
response = requests.request(
|
||||
method=request.method,
|
||||
url=full_url,
|
||||
headers=headers,
|
||||
data=request.get_data(),
|
||||
stream=True
|
||||
)
|
||||
|
||||
logger.info(f"Response status: {response.status_code}")
|
||||
logger.info(f"Response headers: {dict(response.headers)}")
|
||||
|
||||
# Filter out hop-by-hop headers from the response
|
||||
filtered_headers = {k: v for k, v in response.headers.items() if k.lower() not in HOP_BY_HOP_HEADERS}
|
||||
|
||||
return Response(
|
||||
response.iter_content(chunk_size=8192),
|
||||
status=response.status_code,
|
||||
headers=filtered_headers
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Proxy error: {str(e)}", exc_info=True)
|
||||
return str(e), 502
|
||||
|
||||
|
||||
@zrok.decor.zrok(opts=zrok_opts)
|
||||
def run_proxy():
|
||||
# the port is only used to integrate zrok with frameworks that expect a "hostname:port" combo
|
||||
serve(app, port=bindPort)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Start a zrok proxy server')
|
||||
parser.add_argument('target_url', help='Target URL to proxy requests to')
|
||||
parser.add_argument('-n', '--unique-name', help='Unique name for the proxy instance')
|
||||
args = parser.parse_args()
|
||||
|
||||
target_url = args.target_url
|
||||
logger.info("=== Starting proxy server ===")
|
||||
logger.info(f"Target URL: {target_url}")
|
||||
logger.info(f"Logging level: {logger.getEffectiveLevel()}")
|
||||
|
||||
root = zrok.environment.root.Load()
|
||||
my_env = EnvironmentAndResources(
|
||||
environment=None,
|
||||
shares=[]
|
||||
)
|
||||
overview = Overview.create(root=root)
|
||||
for env_stuff in overview.environments:
|
||||
if env_stuff.environment.z_id == root.env.ZitiIdentity:
|
||||
my_env = EnvironmentAndResources(
|
||||
environment=env_stuff.environment,
|
||||
shares=env_stuff.shares
|
||||
)
|
||||
break
|
||||
|
||||
if my_env:
|
||||
logger.debug(
|
||||
f"Found environment in overview with Ziti identity "
|
||||
f"matching local environment: {my_env.environment.z_id}"
|
||||
)
|
||||
else:
|
||||
logger.error("No matching environment found")
|
||||
sys.exit(1)
|
||||
|
||||
existing_reserved_share = None
|
||||
for share in my_env.shares:
|
||||
if share.token == args.unique_name:
|
||||
existing_reserved_share = share
|
||||
break
|
||||
|
||||
if existing_reserved_share:
|
||||
logger.debug(f"Found existing share with token: {existing_reserved_share.token}")
|
||||
shr = Share(Token=existing_reserved_share.token, FrontendEndpoints=[existing_reserved_share.frontend_endpoint])
|
||||
else:
|
||||
logger.debug(f"No existing share found with token: {args.unique_name}")
|
||||
share_request = ShareRequest(
|
||||
BackendMode=zrok.model.PROXY_BACKEND_MODE,
|
||||
ShareMode=zrok.model.PUBLIC_SHARE_MODE,
|
||||
Frontends=['public'],
|
||||
Target="http-proxy",
|
||||
Reserved=True
|
||||
)
|
||||
if args.unique_name:
|
||||
share_request.UniqueName = args.unique_name
|
||||
|
||||
shr = zrok.share.CreateShare(root=root, request=share_request)
|
||||
|
||||
def cleanup():
|
||||
zrok.share.ReleaseReservedShare(root=root, shr=shr)
|
||||
logger.info(f"Share {shr.Token} released")
|
||||
if not args.unique_name:
|
||||
atexit.register(cleanup)
|
||||
|
||||
zrok_opts['cfg'] = zrok.decor.Opts(root=root, shrToken=shr.Token, bindPort=bindPort)
|
||||
|
||||
logger.info(f"Access proxy at: {', '.join(shr.FrontendEndpoints)}")
|
||||
|
||||
run_proxy()
|
Loading…
Reference in New Issue
Block a user