Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce transaction_id policy #1460

Closed

Conversation

tkan145
Copy link
Contributor

@tkan145 tkan145 commented Apr 29, 2024

What

This PR partially support https://issues.redhat.com/browse/THREESCALE-10973. Specially it satisfy the following 2 requirements from the FAPI - baseline profile

  • shall set the response header x-fapi-interaction-id to the value received from the corresponding FAPI client request header or to a RFC4122 UUID value if the request header was not provided to track the interaction, e.g., x-fapi-interaction-id: c770aef3-6784-41f7-8e0e-ff5f97bddb3a;
  • shall log the value of x-fapi-interaction-id in the log entry; and

Why making a new policy and not extend the current Header Modification policy

We can easily extend the current Header Policy and add uuid filter and new option to generate the header in response if it does not exist in request. However, in my opinion this would complicate the logic of the Title Modification policy. For example, If the user sets the include_in_response checkbox while also setting a header in the Response field, and upstream also returns the same header, which header takes precedence?

Also the benefit of having separate policy so we can later extend the support algorithm if need (currently only uuidv4 is supported)

Answer to questions from https://issues.redhat.com/browse/THREESCALE-6577

what if an "XXXXX" (to be defined ID header) is already assigned to the incoming request (e.g. by ingress, or LB or somewhere previously) should that be used instead?

The policy won't modify the header if it exist

Should that be logged by apicast
Is there any interaction with logging policy?

Yes, user should be able to log the header with Logging policy

What if there are multiple apicasts behind an LB, then they can't just use a counter to ensure uniqueness and an apicast GUID would be required.

We use UUID to the change of collision is fairly small

Do this, even if OpenTracing is being used?

I don't have answer to this but I think it's still useful to have this policy as not everyone use OpenTracing.

Verification steps:

  • Create an apicast-config.json file with the following content
cat <<EOF >apicast-config.json
{
  "services": [
    {
      "backend_version": "1",
      "id": "1",
      "proxy": {
        "hosts": [
          "one"
        ],
        "api_backend": "https://echo-api.3scale.net:443",
        "authentication_method": "2",
        "backend": {
          "endpoint": "http://127.0.0.1:8081",
          "host": "backend"
        },
        "policy_chain": [
          {
            "name": "apicast.policy.transaction_id",
            "configuration": {
              "header_name": "X-Transaction-ID",
              "include_in_response": true
            }
          },
          {
            "name": "apicast.policy.apicast"
          },
          {
            "name": "apicast.policy.logging",
            "configuration": {
              "enable_access_logs": false,
              "custom_logging": "\"{{request}}\" to service {{service.id}} and {{service.name}} with ID {{req.headers.x_transaction_id}} - response: {{resp.headers.x_transaction_id}}"
            }
          }
        ],
        "proxy_rules": [
          {
            "http_method": "GET",
            "pattern": "/",
            "metric_system_name": "hits",
            "delta": 1,
            "parameters": [],
            "querystring_parameters": {}
          }
        ]
      }
    }
  ]
}
EOF
  • Checkout this branch and start dev environment
make development
make dependencies
  • Run apicast locally
THREESCALE_DEPLOYMENT_ENV=staging APICAST_LOG_LEVEL=warn APICAST_WORKER=1 APICAST_CONFIGURATION_LOADER=lazy APICAST_CONFIGURATION_CACHE=0 THREESCALE_CONFIG_FILE=apicast-config.json ./bin/apicast
  • Capture apicast IP
APICAST_IP=$(docker inspect apicast_build_0-development-1 | yq e -P '.[0].NetworkSettings.Networks.apicast_build_0_default.IPAddress' -)
  • Send a request
curl -i -k -H "Host: one" "http://${APICAST_IP}:8080/test?user_key="

Check the log for the following line

"GET /test?user_key= HTTP/1.1" to service 1 and  with ID 8806c18d-c71d-4306-8eb3-43a8b538b31a - response: 8806c18d-c71d-4306-8eb3-43a8b538b31a

The response header should also contain the X-Transaction-ID header

HTTP/1.1 200 OK
Server: openresty
Date: Wed, 01 May 2024 08:47:39 GMT
Content-Type: application/json
Content-Length: 642
Connection: keep-alive
x-3scale-echo-api: echo-api/1.0.3
vary: Origin
x-content-type-options: nosniff
x-envoy-upstream-service-time: 0
X-Transaction-ID: 8806c18d-c71d-4306-8eb3-43a8b538b31a

@tkan145 tkan145 force-pushed the THREESCALE-10973-fapi-baseline-profile branch 2 times, most recently from dd81bf7 to 8c47c71 Compare May 1, 2024 06:51
@tkan145 tkan145 force-pushed the THREESCALE-10973-fapi-baseline-profile branch from 8c47c71 to 9c2eb58 Compare May 1, 2024 08:44
@tkan145 tkan145 marked this pull request as ready for review May 1, 2024 09:13
@tkan145 tkan145 requested a review from a team as a code owner May 1, 2024 09:13
Copy link
Member

@eguzki eguzki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

codewise LGTM

Just some nitpicking done

Regarding logger, it has nothing to do with the PR. I guess the logging will be more relevant for the coming FAPI policy.

Also related to logging. If relying only in the existing logging policy for logging x-fapi-interaction-id header value, then the customer needs to have custom logging. The customer loses the "standard" logging format (unless it formats in the same way).

[09/May/2024:12:37:29 +0000] one:8080 172.21.0.1:58962 "GET /test?user_key= HTTP/1.1" 200 646 (0.390) 0

Have you considered adding yet another log line (INFO level) with the transaction ID? Maybe not a good idea.

if not transaction_id or transaction_id == "" then
transaction_id = context.transaction_id
end
ngx.header[self.header_name] = transaction_id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I wonder if this ngx.header[self.header_name] = transaction_id statement should only be executed in case it is not in the headers or empty.

The difference in behavior regarding what you coded is when the response header exists but it is empty. in your case, request transaction ID has preference over empty response header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference in behavior regarding what you coded is when the response header exists but it is empty. in your case, request transaction ID has preference over empty response header.

wouldn't transaction_id == "" already covered that?

Regarding the logging, we have customer complained about extra log line, see THREESCALE-5225. I think the best solution is to inject this ID the the log, similar with what we did for the request-id

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right. I got confused.

The only diff would be that you are setting the value even when it is already set. Which is harmless. It is a matter of style. LGTM.

@eguzki
Copy link
Member

eguzki commented May 9, 2024

I recommend rebasing this and test this with the new openresty 1.21.4.3

@tkan145
Copy link
Contributor Author

tkan145 commented Jun 14, 2024

Close in favor of #1465

@tkan145 tkan145 closed this Jun 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants