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

ability to configure policy chains globally #496

Merged
merged 3 commits into from
Nov 29, 2017
Merged

Conversation

mikz
Copy link
Contributor

@mikz mikz commented Nov 22, 2017

closes #481

It is possible to return a table with field policy_chain that is going to be used as the policy chain instead of the default one.

Example:

local policy_chain = require('apicast.policy_chain').default()

policy_chain:insert(mypolicy)

return {
  policy_chain = policy_chain
}

@mikz mikz force-pushed the configure-policy-chain branch 4 times, most recently from 4574c66 to f2b9201 Compare November 24, 2017 13:32
@mikz mikz changed the title [wip] ability to configure policy chains globally ability to configure policy chains globally Nov 24, 2017
@mikz mikz requested a review from davidor November 24, 2017 13:57
policy_chain:insert(policy_chain.load('apicast.policy.echo'))

return {
policy_chain = policy_chain
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We will have to start documenting the environment config format. It is Lua, so no JSON schema.

@mikz mikz force-pushed the configure-policy-chain branch from 3e32e24 to 9bf402f Compare November 24, 2017 14:10
@@ -92,6 +92,38 @@ describe('policy_chain', function()
end, 'readonly table')
end)

describe('.insert', function()

it('adds policy to the chain', function()
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd modify this test or add a new one. For .insert we need to test that it adds the policy to the end of the list. If we do not initialize the chain with a few elements, we won't be able to test that. This test would pass even if the code added the policy to the beginning of the list or in a random position.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point 👍 Will fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in d340bf1 but going to be squashed.

assert.equal(0, #chain)
end)
end)

Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to test .default for completeness. The other two methods introduced in this PR for that module are tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Fixing 👍

Copy link
Contributor Author

@mikz mikz Nov 27, 2017

Choose a reason for hiding this comment

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

Fixed in 1fbfff8 and will squash it in a rebase.

-- @tparam[opt] int position the position to add the policy to, defaults to last one
function _M:insert(policy, position)
if self.frozen then
return nil, 'frozen chain'
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should be more specific in the error message. Not sure this will be obvious to contributors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the error messages in openresty are pretty simple because people can treat them like error code and match them. I'd probably even go for just 'frozen' so it is easier to match.

Error codes from lua-resty-redis:

  • not initialized
  • not subscribed
  • closed
  • timeout

If "frozen" is not understandable I could rename it to: immutable, finalized, locked (other suggestions welcome).

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough. I was thinking more about clarifying what the error is about to possible contributors rather than making sure it's easy to match.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That probably should be addressed by the method documentation describing the error messages. Will do 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in f4be8fb and going to be squashed.

@@ -96,6 +109,25 @@ function _M:export()
return chain
end

--- Freeze the policy chain to prevent modifications.
-- After calling this method it won't be possible to insert more policies.
-- @treturn self
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: missing type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

This file is probably not generating the doc as we had a whitelist in config.ld.

Will add it there and see the generated documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed f4be8fb and going to be squashed.

@@ -0,0 +1,7 @@
local policy_chain = require('apicast.policy_chain').build({ })
Copy link
Contributor

Choose a reason for hiding this comment

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

I think these 2 lines could be simplified to:
local policy_chain = require('apicast.policy_chain').build({'apicast.policy.echo'})

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I wanted to show the :insert as an example. But that would be better with the default chain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about:

local policy_chain = require('apicast.policy_chain').default()
local echo = require('apicast.policy.echo').new({ exit = 0 })

policy_chain:insert(echo, 1)

?

It shows off the insert - how to extend the default chain and how to pass options to policy.

Copy link
Contributor

Choose a reason for hiding this comment

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

But apicast.policy.echo doesn't have a constructor that can receive that table.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well I'd change it to accept a configuration for sake of the example.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK. In that case, I think that the latest example looks better than the original one 👍

Copy link
Contributor Author

@mikz mikz Nov 28, 2017

Choose a reason for hiding this comment

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

Fixed in 02ad4ab and going to be squashed or extracted into own commit.

@@ -0,0 +1,7 @@
local policy_chain = require('apicast.policy_chain').build({ })

policy_chain:insert(policy_chain.load('apicast.policy.echo'))
Copy link
Contributor

Choose a reason for hiding this comment

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

This insert + load combination looks a bit confusing to me. I wonder if we should make .load private.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And just rely on require(...).new() instead of .load ?

Copy link
Contributor

Choose a reason for hiding this comment

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

What about .insert calling .load like .build does and making .load private?

I think that policy_chain:insert('apicast.policy.echo') or policy_chain:insert(echo.new(something)) looks better than policy_chain:insert(policy_chain.load(...)).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd like insert to be an API that does one thing only. So I'd prefer it does not initialize the module because then it would also accept the configuration.

I agree .load is kind of an useless abstraction and it would be better to use plain require. The only reason for is existence was that I wanted to have an abstraction so the internals can be replaced without much hassle.
But when replacing internal and for example changing :new to .new the policies would have to change anyway and it would leak this concept to the policy. But at least all the uses of the policy would not have to change.

So we should agree if we want to expose the policy initialization to users and deal with the consequences if we need to ever change it or expose some method to load/initialize policies.

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 new example looks like 02ad4ab so it uses plain require. Guess that is ok for now.

$ENV{APICAST_CONFIGURATION_LOADER} = 'boot';
$ENV{THREESCALE_CONFIG_FILE} = 't/servroot/html/config.json';
#$ENV{TEST_NGINX_NO_CLEAN} = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Commented.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well spotted. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 19a3bb8 and will be squashed.


local template = Template:new(context, dir, true)
local function apicast_root()
return resty_env.get('APICAST_DIR') or pl.path.abspath('.')
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we call .value instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Good point!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did mass change in 569c520 and will squash it.

local function openresty_binary(candidates)
return resty_env.value('APICAST_OPENRESTY_BINARY') or
resty_env.value('TEST_NGINX_BINARY') or
pick_openesty(candidates)
Copy link
Contributor

Choose a reason for hiding this comment

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

typo, also, I find naming here a bit confusing. This method is choosing the openresty binary but it's calling one named pick_openresty.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I was too lazy to rename this function. Will do 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in d5a7ca0 and will squash it.

insert(nameservers, tostring(nameserver))
end

if #nameservers > 0 then
Copy link
Contributor

Choose a reason for hiding this comment

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

Why return nil instead of {} ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because then it is easier to verify that there are no nameservers. resolver directive in the nginx conf has to have at least one server. So if there are none we can't set it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to document this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hopefully 5aa2e0c is clear enough and describes that the type of this can be a table of strings or nil. Would that be enough?

@@ -0,0 +1,129 @@
local pl_path = require('pl.path')
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to document the purpose of this module.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, Opened #500 so we can see the documentation artifacts and verify it looks correctly. Will write it after that one is merged and I can see the documetation.

Copy link
Contributor Author

@mikz mikz Nov 28, 2017

Choose a reason for hiding this comment

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

Documented in 5aa2e0c but going to squash it with the commit that introduced it.

@davidor
Copy link
Contributor

davidor commented Nov 27, 2017

I think it would be good to add an integration test that shows how to configure policy chains via environment.

@mikz
Copy link
Contributor Author

mikz commented Nov 27, 2017

@davidor yep that is a good idea 👍 Will do.

@mikz mikz force-pushed the configure-policy-chain branch from 9bf402f to 5aa2e0c Compare November 27, 2017 16:44
local _M = {}
---
-- @field default_environment Default environment name.
-- @table self
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Couldn't figure out a better way to document this. This actually means there would be a property self of the module returned by this file.
But there is no way I could find to have properties of the module just plain values with description. Only tables can be properties of the module and only tables can have fields.

returning policy_chain from the environment configuration
will use that policy chain in nginx
@mikz mikz force-pushed the configure-policy-chain branch from 90017b4 to ee195d9 Compare November 28, 2017 16:40
@mikz mikz requested a review from davidor November 28, 2017 16:44
@@ -0,0 +1,8 @@
local policy_chain = require('apicast.policy_chain').default()
Copy link
Contributor

Choose a reason for hiding this comment

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

examples/configurationcontains many examples for different things. I think it'd be good from now on to explain what each one of them is about. A sentence at the begginning of the file should be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. This one probably should be in own folder.

@@ -1,9 +1,22 @@
local policy = require('apicast.policy')
local _M = policy.new('Echo Policy')
local _M = require('apicast.policy').new('Echo Policy')
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to the comment above. This policy is trivial, but thinking about future contributors, I think that a description of 1 or 2 lines would help.

Copy link
Contributor

@davidor davidor left a comment

Choose a reason for hiding this comment

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

As I pointed out in the comments, I think there are a couple of descriptions that we need to add. Apart from that, looks good.

👌

so enironment configurations can do conversions
@mikz mikz force-pushed the configure-policy-chain branch from 464eff0 to 506c694 Compare November 29, 2017 08:57
@mikz mikz requested a review from davidor November 29, 2017 08:58
@mikz mikz force-pushed the configure-policy-chain branch 2 times, most recently from c7834b5 to a63eccc Compare November 29, 2017 09:18
* show how environment configuration can define a policy_chain
* show that it has access to ENV
* change echo policy to have more granular configuration options
@mikz mikz force-pushed the configure-policy-chain branch from a63eccc to 024363b Compare November 29, 2017 09:19
@davidor davidor merged commit 2857766 into master Nov 29, 2017
@davidor davidor deleted the configure-policy-chain branch November 29, 2017 09:37
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.

Provide config to set global policies
2 participants