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

feat(config) flexible tokens/headers configuration #3300

Closed
wants to merge 1 commit into from

Conversation

hbagdi
Copy link
Member

@hbagdi hbagdi commented Mar 15, 2018

Instead of introducing a config option for each
and every header or set of headers, an array of
these values can be now specified using the headers
config option.

Only headers or tokens specified in the headers will
be set by Kong when applicable.

The goal here is to move towards a simpler and
easier to understand configuration, similar to
1b9976f (#3147).

@hbagdi hbagdi added the pr/wip A work in progress PR opened to receive feedback label Mar 15, 2018
@hbagdi
Copy link
Member Author

hbagdi commented Mar 15, 2018

@thibaultcha Does this look like the right way to go forward?

@thibaultcha
Copy link
Member

@hbagdi Nice! It looks like there is more work that needs to happen still (we can improve the "sugar" and make the checks more readable probably, + style issues), but otherwise it looks like it is on the right track :)

@@ -11,7 +11,9 @@ local utils = require "kong.tools.utils"
local log = require "kong.cmd.utils.log"
local ip = require "kong.tools.ip"
local ciphers = require "kong.tools.ciphers"
local bit = require "bit"
Copy link
Member

Choose a reason for hiding this comment

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

let's keep this simple:

local bit = require "bit"


local bor = bit.bor
Copy link
Member

Choose a reason for hiding this comment

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

no need to cache that as an upvalue, in fact not doing so might provide more readable code in this particular case (bit.bor being more specific than bor). This is also not a global, nor is this a hot code path, nor is the function name long, so...

if token == "off" then
mask = 0
break
elseif allowed[token] == nil then -- TODO what about case sensetive??
Copy link
Member

Choose a reason for hiding this comment

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

style: need line jump before this line

Copy link
Member

Choose a reason for hiding this comment

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

It's ok to be case-sensitive imho, and expect server and not SERVER or ServER.

break
elseif allowed[token] == nil then -- TODO what about case sensetive??
errors[#errors+1] = "tokens: invalid entry '" .. tostring(token) .. "'"
else
Copy link
Member

Choose a reason for hiding this comment

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

style: ditto (line jump)

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry about all the styling issues in this (and all the previous) PR. I need to figure out my styling and code convention issues.

local bit = require "bit"


local bor = bit.bor
Copy link
Member

Choose a reason for hiding this comment

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

ditto, these 2 instructions are adding quite a lot of whitespaces and blank lines

@@ -56,7 +59,7 @@ return function(ngx)
local status = ngx.status
message = BODIES["s" .. status] and BODIES["s" .. status] or format(BODIES.default, status)

if singletons.configuration.server_tokens then
if band(constants.HEADER_MASKS[constants.HEADERS.SERVER], singletons.configuration.header_mask) then
Copy link
Member

Choose a reason for hiding this comment

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

Thinking about this, we can probably optimize this by building a table in conf_loader that we can query like so:

local config = singletons.config
if config.header_tokens.server then
  -- ...
end

if config.header_tokens.via then
  -- ...
end

This way we save both the AND operation, and simplify the readability of those conditions.

Copy link
Member Author

Choose a reason for hiding this comment

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

This makes a lot of sense and gets rid off all the bit operations all together.

-- in conf_loader.load()
local headers = {
  [headers.PROXY_LATENCY] = false,
  [headers.UPSTREAM_LATENCY] = false,
  [headers.SERVER] = false,
  [headers.VIA] = false,
}

-- loop through headers field in configuration and update above table 

-- and finally
config.headers = headers

One question,
Do we want to have server_tokens or latency_tokens boolean in our singleton configuration table or having only header granularity is enough? We will still have the above tokens in the config file as sugar which simply enable the set of headers.

[headers.UPSTREAM_LATENCY] = 0x02,
[headers.SERVER] = 0x04,
[headers.VIA] = 0x08,
latency = bor(0x01,0x02),
Copy link
Member

Choose a reason for hiding this comment

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

Now that this property refers to multiple headers, this should be latencies I believe

[headers.SERVER] = 0x04,
[headers.VIA] = 0x08,
latency = bor(0x01,0x02),
server = bor(0x04,0x08),
Copy link
Member

Choose a reason for hiding this comment

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

This one could be server_tokens (and the property in the configuration could be headers probably?) Sorry if I mislead you while drafting the quick implementation on the fly while we chatted. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

I put in names just as placeholders since I was having a difficult time in deciding on which one to chose.

headers as a property in user visible configuration property is much easier to grok.
I understand that server_tokens is coming from NGINX world and we would like to stick to the conventions but could that instead be server_names? Is it a bit more descriptive?
I'm thinking:

headers = server_names, kong_latencies, X-Kong-Foo-Bar

@hbagdi hbagdi force-pushed the feat/tokens-config branch from a8d94f4 to f5890bf Compare March 19, 2018 20:05
[headers.SERVER] = false,
[headers.VIA] = false,
server_tokens = false,
latency_tokens = false,
Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure if *_tokens are needed here.

header_tokens[headers.UPSTREAM_LATENCY] = true
end
end
conf.headers = header_tokens
Copy link
Member Author

Choose a reason for hiding this comment

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

conf.headers = build_headers_table(conf.headers)

?

Copy link
Member

Choose a reason for hiding this comment

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

In check_and_infer, we should only do validation (the errors[#errors+1] = ... part). Below and once we know all values are correct, we can mutate the conf.headers table.

@hbagdi hbagdi added pr/please review and removed pr/wip A work in progress PR opened to receive feedback labels Mar 19, 2018
@@ -80,7 +80,7 @@ describe("Server Tokens", function()

setup(start {
nginx_conf = "spec/fixtures/custom_nginx.template",
server_tokens = "on",
headers = "server_tokens",
Copy link
Member Author

Choose a reason for hiding this comment

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

@thibaultcha what is the approach to put new tests? Should they go into both spec and spec-old-api? '
I think only in spec but want to confirm

Copy link
Member

Choose a reason for hiding this comment

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

Yes, just spec. old-spec is for backards-compatibility with 0.12 and the API entity

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the quick response!

@hbagdi hbagdi force-pushed the feat/tokens-config branch from 3594cc5 to 47a8024 Compare March 20, 2018 02:46
@hbagdi hbagdi changed the title WIP: feat(config) flexible tokens/headers configuration feat(config) flexible tokens/headers configuration Mar 20, 2018
@hbagdi hbagdi force-pushed the feat/tokens-config branch from 47a8024 to 2d5437a Compare March 20, 2018 02:55
@hbagdi
Copy link
Member Author

hbagdi commented Apr 3, 2018

@thibaultcha ping

Copy link
Member

@thibaultcha thibaultcha left a comment

Choose a reason for hiding this comment

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

This is looking really good, but still a few items to fix before we can merge it.

break

elseif header_tokens[token] == nil then
errors[#errors+1] = "tokens: invalid entry '" .. tostring(token) .. "'"
Copy link
Member

Choose a reason for hiding this comment

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

prefix should be "headers: ..."?

Copy link
Member

Choose a reason for hiding this comment

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

We also need tests for this error which I don't see any for?

Copy link
Member Author

Choose a reason for hiding this comment

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

Addressed both of these in the updated commit.

header_tokens[headers.UPSTREAM_LATENCY] = true
end
end
conf.headers = header_tokens
Copy link
Member

Choose a reason for hiding this comment

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

In check_and_infer, we should only do validation (the errors[#errors+1] = ... part). Below and once we know all values are correct, we can mutate the conf.headers table.

header[constants.HEADERS.UPSTREAM_LATENCY] = ctx.KONG_WAITING_TIME
end

if singletons.configuration.headers[constants.HEADERS.PROXY_LATENCY] then
Copy link
Member

Choose a reason for hiding this comment

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

style: the line below has now has a weird looking assignment operator with too many spaces, fixing it should be in the scope of this PR

Copy link
Member Author

Choose a reason for hiding this comment

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

Apologies for this one!

@hbagdi hbagdi force-pushed the feat/tokens-config branch 2 times, most recently from 0dbec50 to 37713c6 Compare April 13, 2018 14:32
-- load headers configuration
for _, token in ipairs(conf.headers) do
if token == "off" then
break
Copy link
Member

Choose a reason for hiding this comment

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

This behaviour is slightly off with that of the new directives like proxy_listen - fixing it should be easy.

In the new listeners directives, off only has meaning if it is the first value:

proxy_listen = off, ...

With this headers directive however, the following is possible but slightly confusing:

headers = latency_tokens, off, server_tokens

Here, we end up in a situation where "half" of the specified tokens were taken into consideration. This could have (arguably) been considered an acceptable behaviour, but better stay consistent with the stricter semantics of the *_listen directives imho. So the above would set both latency_tokens and server_tokens, and to disable headers, one must do:

headers = off

Frankly, the off flag probably should not be mixed with actual values (that is bad implementation from the listeners directives to accept that imho), but well, not the scope of this PR to address, and better stick to this behaviour for now probably.

The above validation can probably implement the same behaviour (or ignore "off" values altogether, thus validating all non-off values in this list, up to you).

@hbagdi
Copy link
Member Author

hbagdi commented Apr 18, 2018

With this headers directive however, the following is possible but slightly confusing:

headers = latency_tokens, off, server_tokens

Here, we end up in a situation where "half" of the specified tokens were taken into consideration. This could have (arguably) been considered an acceptable behaviour, but better stay consistent with the stricter semantics of the *_listen directives imho. So the above would set both latency_tokens and server_tokens, and to disable headers, one must do:

headers = off

Frankly, the off flag probably should not be mixed with actual values (that is bad implementation from the listeners directives to accept that imho), but well, not the scope of this PR to address, and better stick to this behaviour for now probably.

I expected that this comment was coming.
I thought about this while writing the code but brushed it off with a corner case that is unlikely to happen. An empty value would suite well as an "off" but IIRC Penlight removes empty strings.

I've updated the code to match the behavior you describe above and added a test for it.

An explicit solution would be to check for a mix of off and other valid values in check_and_infer and throw an error.

This is looking really good, but still a few items to fix before we can merge it.

Let me know if there's anything other than the off value issue that needs to be fixed.

@hbagdi hbagdi force-pushed the feat/tokens-config branch from 37713c6 to 4e34d1c Compare April 18, 2018 16:00
for _, token in ipairs(conf.headers) do
if token ~= "off" then
header_tokens_clone[token] = true
end
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure how this behaviour is different from yesterday's version of this patch? It still doesn't seem like it follows the same approach as other array-like directives that accept off?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, I see. If the first element is off then turn it off else don't. My bad.

-- load headers configuration
for _, token in ipairs(conf.headers) do
if token ~= "off" then
header_tokens_clone[token] = true
Copy link
Member

Choose a reason for hiding this comment

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

I think we should allow for case-insensitive values when specifying headers in this directive (just like HTTP headers are). E.g.:

  headers = latency_tokens, Via
is same as:
  headers = latency_tokens, via

@hbagdi hbagdi force-pushed the feat/tokens-config branch 5 times, most recently from 9fc3ccf to 5bcc063 Compare April 19, 2018 15:37
As new headers are introduced by Kong's core,
instead of introducing a config option for each
and every header or set of headers, an array of
these values can be now specified using the `headers`
config option.

This offers a fine grained controlled and
does not blow up the number of configuration options.

The goal here is to move towards a  simpler and
easier to understand configuration, similar to
1b9976f (#3147).
@hbagdi hbagdi force-pushed the feat/tokens-config branch from 5bcc063 to 5afad1e Compare April 20, 2018 03:03
@hbagdi
Copy link
Member Author

hbagdi commented Apr 20, 2018

@thibaultcha Updated the PR with the requested fixes.

thibaultcha pushed a commit that referenced this pull request Apr 20, 2018
As new headers are introduced by Kong's core, instead of introducing a
config option for each and every header or set of headers, an array of
these values can be now specified using the `headers` config option.

This offers a fine grained controlled and does not blow up the number of
configuration options.

The goal here is to move towards a  simpler and easier to understand
configuration, similar to 1b9976f (#3147).

From #3300

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
@thibaultcha
Copy link
Member

Merged! Thank you!

@thibaultcha thibaultcha deleted the feat/tokens-config branch April 20, 2018 05:54
hbagdi added a commit that referenced this pull request Apr 26, 2018
This fixes a bug introduced in 976dd87 (#3300)
where headers config option was being overwritten
as a table. The table is not persisted in the intermediate
config file and hence the config option does not take effect.
hbagdi added a commit that referenced this pull request Apr 27, 2018
This fixes a bug introduced in 976dd87 (#3300)
where headers config option was being overwritten
as a table. The table is not persisted in the intermediate
config file and hence the config option does not take effect.

This commit also exposes `get_running_conf` helper function to
read conf from prefix directory in use during the current test.
hbagdi added a commit that referenced this pull request May 1, 2018
This fixes a bug introduced in 976dd87 (#3300)
where headers config option was being overwritten
as a table. The table is not persisted in the intermediate
config file and hence the config option does not take effect.
thibaultcha pushed a commit that referenced this pull request May 3, 2018
This fixes a bug introduced in 976dd87 (#3300) where the `headers`
config option were not properly written to `.kong_env`. This would be an
issue when the value was specified from the configuration file (vs. via
environment variables).

From #3419

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
hbagdi added a commit to Kong/docs.konghq.com that referenced this pull request May 29, 2018
With CE 0.14.0, a new `headers` configuration option is
introduced and `server_tokens` and `latency_tokens` are removed.

See Kong/kong#3300

Signed-off-by: Harry Bagdi <harrybagdi@gmail.com>
hbagdi added a commit to Kong/docs.konghq.com that referenced this pull request May 31, 2018
With CE 0.14.0, a new `headers` configuration option is
introduced and `server_tokens` and `latency_tokens` are removed.

See Kong/kong#3300

Signed-off-by: Harry Bagdi <harrybagdi@gmail.com>
hbagdi added a commit to Kong/docs.konghq.com that referenced this pull request May 31, 2018
With CE 0.14.0, a new `headers` configuration option is
introduced and `server_tokens` and `latency_tokens` are removed.

See Kong/kong#3300

Signed-off-by: Harry Bagdi <harrybagdi@gmail.com>
hbagdi added a commit to Kong/docs.konghq.com that referenced this pull request Jun 22, 2018
With CE 0.14.0, a new `headers` configuration option is
introduced and `server_tokens` and `latency_tokens` are removed.

See Kong/kong#3300
thibaultcha pushed a commit to Kong/docs.konghq.com that referenced this pull request Jun 22, 2018
With CE 0.14.0, a new `headers` configuration option is introduced and
`server_tokens` and `latency_tokens` are removed.

See Kong/kong#3300

From #729
thibaultcha pushed a commit to Kong/docs.konghq.com that referenced this pull request Jun 28, 2018
With CE 0.14.0, a new `headers` configuration option is introduced and
`server_tokens` and `latency_tokens` are removed.

See Kong/kong#3300

From #729
ukiahsmith pushed a commit to Kong/docs.konghq.com that referenced this pull request Jul 2, 2018
With CE 0.14.0, a new `headers` configuration option is introduced and
`server_tokens` and `latency_tokens` are removed.

See Kong/kong#3300

From #729
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