# README
Cloud Receptor Controller
The Cloud Receptor Controller is designed to receive work requests from internal clients and route the work requests to the target receptor node which runs in the customer's environment.
Submitting A Work Request
A work request can be submitted by sending a work request message to the /job endpoint.
$ curl -v -X POST -d '{"account": "01", "recipient": "node-b", "payload": "fix_an_issue", "directive": "workername:action"}' -H "x-rh-identity:eyJpZGVudGl0eSI6IHsiYWNjb3VudF9udW1iZXIiOiAiMDAwMDAwMSIsICJpbnRlcm5hbCI6IHsib3JnX2lkIjogIjAwMDAwMSJ9fX0=" http://localhost:9090/job
Work Request Message Format
{
"account": <account number>,
"recipient": <node id of the receptor node>,
"payload": <work reqeust payload>,
"directive": <work request directive (for example: "workername:action">
}
Work Request Response Message Format
{
"id": <uuid for the work request>
}
Get a list of open connections
The list of open connections can be retrieved by sending a GET to the /connection endpoint.
$ curl -H "x-rh-identity:eyJpZGVudGl0eSI6IHsiYWNjb3VudF9udW1iZXIiOiAiMDAwMDAwMSIsICJpbnRlcm5hbCI6IHsib3JnX2lkIjogIjAwMDAwMSJ9fX0=" http://localhost:9090/connection
Connection List Response Message Format
{
"connections": [
{
"account": "0000001",
"connections": [
"node-a",
"node-b"
]
},
{
"account": "0000002",
"connections": [
"node-c"
]
}
]
}
Checking the status of a connection
The status of a connection can be checked by sending a POST to the /connection/status endpoint.
$ curl -v -X POST -d '{"account": "02", "node_id": "1234"}' -H "x-rh-identity:eyJpZGVudGl0eSI6IHsiYWNjb3VudF9udW1iZXIiOiAiMDAwMDAwMSIsICJpbnRlcm5hbCI6IHsib3JnX2lkIjogIjAwMDAwMSJ9fX0=" http://localhost:9090/connection/status
Connection Status Request Message Format
{
"account": <account number>,
"node_id": <node id of the receptor node>,
}
Connection Status Response Message Format
{
"status":"connected" or "disconnected"
"capabilities": {
"max_work_threads": 12,
"worker_versions": {
"receptor_http": "1.0.0"
}
}
}
Sending a ping
A ping request can be sent by sending a POST to the /connection/ping endpoint.
$ curl -v -X POST -d '{"account": "02", "node_id": "1234"}' -H "x-rh-identity:eyJpZGVudGl0eSI6IHsiYWNjb3VudF9udW1iZXIiOiAiMDAwMDAwMSIsICJpbnRlcm5hbCI6IHsib3JnX2lkIjogIjAwMDAwMSJ9fX0=" http://localhost:9090/connection/ping
Ping Request Message Format
{
"account": <account number>,
"node_id": <node id of the receptor node>,
}
Ping Response Message Format
The response from the ping is similar to the response that is put onto the kafka message queue:
{
"status":"connected" or "disconnected"
"payload":
{
"account": <account number>,
"sender": <node that send the response>
"message_type": <message type from the receptor network, usually "response">
"message_id": <uuid of the message from the receptor network>
"payload": <response payload from the receptor network>
"code": 0,
"in_response_to": <uuid of the message that this message is in response to>
"serial": 1
}
}
If there is not a websocket connection to the node, then the status will be "disconnected" and the payload will be null.
Kafka Topics
The receptor controller will utilize two kafka topics:
- Consume jobs from:
platform.receptor-controller.jobs
- Produce job responses to:
platform.receptor-controller.responses
The response will contain the following information:
- response key: MessageID
- response value: json containing Account, Sender, MessageID, MessageType, Payload, Code, and InResponseTo
- example response from a ping:
426f674d-42d5-11ea-bea3-54e1ad81c0b2: {"account":"0000001","sender":"node-a","message_id":"b959e674-4a2d-48be-88e3-8bb44000f040","code": 0,"message_type": "response","payload":"{\"initial_time\": \"2020-01-29T20:23:49,811218829+00:00\", \"response_time\": \"2020-01-29 20:23:49.830491\", \"active_work\": []}", "in_response_to": "426f674d-42d5-11ea-bea3-54e1ad81c0b2"}
The key for the message on the kafka topic will be the message id that was returned by the receptor-controller when the original message was submitted. The message_id will be the message id as it is passed along from the receptor mesh network. The in_response_to will be the in_response_to value as it is passed along from the receptor mesh network. The key for the response message and the in_response_to value can be used to match the response to the original message.
The code and message_type field as passed as is from the receptor mesh network. The code can be used to determine if the message was able to be handed over to a plugin and processed successfully (code=0) or if the plugin failed to process the message (code=1). The message_type field can be either "response" or "eof". If the value is "response", then the plugin has not completed processing and more responses are expected. If the value is "eof", then the plugin has completed processing and no more responses are expected.
Connecting via Pre-Shared Key
Internal services (not going through 3scale) can authenticate via a pre-shared key by adding the following headers to a request:
- x-rh-receptor-controller-client-id
- x-rh-receptor-controller-account
- x-rh-receptor-controller-psk
If your service is internal and will not be passing requests through 3scale a psk will be provided. This psk will be unique to your service.
Local testing example:
$ export RECEPTOR_CONTROLLER_SERVICE_TO_SERVICE_CREDENTIALS='{"test_client_1": "12345", "test_client_2": "6789"}'
Example work request using token auth:
$ curl -v -X POST -d '{"account": "01", "recipient": "node-b", "payload": "fix_an_issue", "directive": "workername:action"}' -H "x-rh-receptor-controller-client-id:test_client_1" -H "x-rh-receptor-controller-account:0001" -H "x-rh-receptor-controller-psk:12345" http://localhost:9090/job
Debugging with pprof
To view data gathered by pprof the /debug
endpoint needs to be enabled. You can enable this endpoint by exporting the following variable:
- $ export RECEPTOR_CONTROLLER_ENABLE_PROFILE=true
The profiles can be viewed by going to localhost:9090/debug/pprof
in a browser. Profiles can also be viewed interactively through the command line:
- $ go tool pprof localhost:9090/debug/pprof/allocs (or a different profile)
The above command will open an interactive terminal that can be used to go through the stack traces.
Development
Install the project dependencies:
$ make deps
Building
$ make
Local testing with receptor
Start the server
$ ./gateway
Receptor node configuration
Use the receptor's --peer option to configure a receptor node to connect to the platform receptor controller. The url used with the --peer option should look like ws://localhost:8080/wss/receptor-controller/gateway.
The following command can be used to connect a local receptor node to a local receptor controller:
$ python -m receptor --debug -d /tmp/node-b --node-id=node-b node --peer=ws://localhost:8080/wss/receptor-controller/gateway --peer=receptor://localhost:8889/
Testing
Run the unit tests:
$ make test
Verbose output from the tests:
$ TEST_ARGS="-v" make test
Run specific tests:
$ TEST_ARGS="-run TestReadMessage -v" make test
Test coverage:
$ make coverage
...
...
file:///home/dehort/dev/go/src/github.com/RedHatInsights/platform-receptor-controller/coverage.html
Load the coverage.html file in your browser