Developing Callouts
This repository provides the following files to be extended:
CalloutServer: Baseline service callout server.
CalloutTools: Common functions for callout servers.
Creating a New Server
Create a New Server Script:
Create
server.py
and import theCalloutServer
class:from extproc.service.callout_server import CalloutServer
Just from importing the server class we can make the server run by creating a new instance and calling the blocking function
run
:if __name__ == '__main__': CalloutServer().run()
Extend CalloutServer:
Calling the server like this won’t do much besides respond to health checks. For the server to respond to callouts, we create a custom class extending
CalloutServer
.Make a class extending
CalloutServer
:class BasicCalloutServer(CalloutServer): def on_response_headers(self, headers: HttpHeaders, context: ServicerContext) -> HeadersResponse: ...
There are a few callback methods in
CalloutServer
provided for developers to override:on_request_headers
: Process request headers.on_response_headers
: Process response headers.on_request_body
: Process request body.on_response_body
: Process response body.
These functions correspond to the
oneof
required field in a ProcessingRequest and required response field of a ProcessingResponse.Add Required Imports:
A few things to note here: we are strongly typing our variables with the expected types. This requires the following imports:
from grpc import ServicerContext from envoy.service.ext_proc.v3.external_processor_pb2 import HeadersResponse, HttpHeaders
See Using the proto files for more details.
Each of the callback methods provides the given data type as an input parameter and expects the corresponding response to be returned. For example
on_response_headers
:headers
:response_headers
data from ProcessingRequest.context
: associated grpc data.return
:response_headers
data from ProcessingResponse.
There are methods specified under CalloutTools that will help in creating a response to the callout. Import those with:
from extproc.service.callout_tools import add_header_mutation
Implement Callbacks:
With the callout from before, we can add the
foo:bar
header mutation on incomingresponse_headers
callouts:class BasicCalloutServer(CalloutServer): def on_response_headers(self, headers: HttpHeaders, context: ServicerContext) -> HeadersResponse: return add_header_mutation(add=[('foo', 'bar')])
add_header_mutation
also has parameters for removing (remove) and cache clearing (clear_route_cache). See CalloutTools .Enable Logging:
The callout server uses the
logging
module. By default, this means that nothing is logged to the terminal on standard use. We recommend setting the logging level toINFO
so that normal server operation is visible.import logging if __name__ == '__main__': logging.basicConfig(level=logging.INFO) BasicCalloutServer().run()
Complete Example:
import logging from grpc import ServicerContext from envoy.service.ext_proc.v3.external_processor_pb2 import HeadersResponse from envoy.service.ext_proc.v3.external_processor_pb2 import HttpHeaders from extproc.service.callout_server import CalloutServer from extproc.service.callout_tools import add_header_mutation class BasicCalloutServer(CalloutServer): def on_response_headers(self, headers: HttpHeaders, context: ServicerContext) -> HeadersResponse: return add_header_mutation(add=[('foo', 'bar')]) if __name__ == '__main__': logging.basicConfig(level=logging.INFO) BasicCalloutServer().run()
Additional Details
CalloutServer has many options to customize the security information as well as port settings. The default CalloutServer
listens on port 8443
for grpc traffic, 8000
for health checks, and 8080
for plaintext traffic. Please see the CalloutServer
docstring for more information.
The on_request_headers
and on_request_body
methods also accept ImmediateResponse values as a return value.
CalloutServer also contains a process
method that can be overridden to work directly on incoming ProcessingRequest
.
Using the Proto Files
Import proto classes using the relative envoy/api path:
from envoy.service.ext_proc.v3 import external_processor_pb2
For example, to import the HeadersResponse
class:
from envoy.service.ext_proc.v3.external_processor_pb2 import HeadersResponse