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(core) exposing rewrite_by_lua handler to plugins #2354

Closed
wants to merge 6 commits into from

Conversation

subnetmarco
Copy link
Member

@subnetmarco subnetmarco commented Apr 6, 2017

  • The rewrite_by_lua event can now be implemented by plugins.
  • Introduced no_api in the plugin's schema to determine if a plugin can be applied to a specific API.

@subnetmarco subnetmarco force-pushed the feat/rewrite-by-lua branch from 4b25115 to 37508c2 Compare April 6, 2017 22:00
@subnetmarco
Copy link
Member Author

I have added a test that demonstrates rewriting a random URI to a URI that will later matched to an API.

@subnetmarco subnetmarco force-pushed the feat/rewrite-by-lua branch from 37508c2 to 96dfc2b Compare April 6, 2017 22:01
@Tieske
Copy link
Member

Tieske commented Apr 6, 2017

do we need this for some reason? if not urgent, maybe better to postpone until a new plugin api has been designed?

@subnetmarco
Copy link
Member Author

do we need this for some reason?

Business requirements 😄.

kong/kong.lua Outdated
core.rewrite.before()

for _, plugin in ipairs(singletons.loaded_plugins) do
plugin.handler:rewrite()
Copy link
Member

Choose a reason for hiding this comment

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

This currently runs the handler on every plugin loaded in the system. Say we now have some 25 plugins, so on every request we're now invoking 25 plugins. Not just configured ones, but all available ones.

As the rewrite phase does not have a consumer yet, and also doesn't have an api yet, the only plugins that should be selected here are the global ones.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point - I will update the PR to only chose plugins where api_id == nil and consumer_id == nil.

Copy link
Member Author

Choose a reason for hiding this comment

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

@Tieske done


core.rewrite.after()
end

Copy link
Member

Choose a reason for hiding this comment

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

the above runs on loaded_plugins which means that it will run all plugins available, no matter what. So the user has no control on whether it runs or not, when it is in the system, it will execute.

It should fetch the plugins from the database, and execute only those that are neither attached to a consumer, nor to an api (eg. the ones that already run on every api).

btw, can't we bring the api detection forward, to run in the core.rewrite.before() handler? not sure what it takes, but then we can run plugins like in any phase, including "per api" configured plugins

Copy link
Member Author

Choose a reason for hiding this comment

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

the above runs on loaded_plugins which means that it will run all plugins available, no matter what.

I understand your point but it would be over-optimization IMHO. Currently every other handler also runs on every plugin regardless if they have an event handler associated or not (ie, the access() for every plugin is invoked regardless if the plugin implements that method).

btw, can't we bring the api detection forward, to run in the core.rewrite.before() handler? not sure what it takes, but then we can run plugins like in any phase, including "per api" configured plugins

My use-case is to implement URL rewriting before the APIs are matched, and rewrite the URI to be matched later by the router.

Copy link
Member

Choose a reason for hiding this comment

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

ie, the access() for every plugin is invoked regardless if the plugin implements that method

That's not what I mean. Because that access handler is only called if the user explcitly added that plugin through the management api.

In the code you have now, it will run the handler, even if the user did not configure it. Just a plugin "being in the system" will make it being executed.

Copy link
Member

Choose a reason for hiding this comment

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

hence if you run only the plugins that have been globally added by the user, neither attached to a consumer nor an api, it would work. And it would be up to the user to whether to add this plugin or not.

Copy link
Member

Choose a reason for hiding this comment

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

one more thing: does it currently honour the plugin priority setting?

Copy link
Member Author

Choose a reason for hiding this comment

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

no_api and no_consumer make sure that the plugin cannot be applied to a specific consumer or API, because in the rewrite phase we cannot possibly know who the consumer is and what API he is trying to consume.

With the last commit I am only executing the rewrite() check for those plugins that satisfy the requirement.

Copy link
Member

Choose a reason for hiding this comment

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

There are two ways to approach this problem

  1. add the no_api flag: run only plugins that have no_consumer and no_api set. This causes a plugin to be configurable ONLY as a global plugin
  2. execute the rewrite handler only for globally configured plugins, without adding the extra complexity of a no_api flag. This allows a plugin to be used either as a global, or api/consumer specific plugin. In the latter case the rewrite handler won't be used. But that is then up to the plugin author...

I find option 1 to be A) more complex due to the extra flag, 2) needlessly limiting flexibility

Copy link
Member

Choose a reason for hiding this comment

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

Option 3: use option 2 above (so select only global plugins when running the rewrite handler), but still add the no_api flag. This allows the author to specify the extra limitation only if his plugin needs it.

Copy link
Member Author

Choose a reason for hiding this comment

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

@Tieske no_api is important because it prevents, from the Admin API, to target a specific API when it doesn't make any sense to do so (like no_consumer).

Copy link
Member

Choose a reason for hiding this comment

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

@thefosk That's the option 3 above, which is nice. But that is a limitation that kicks in when configuring. But you should not be using that field to select the plugins to run, you should run all plugins that are configured as global, so where consumer_id and api_id are nil.

Running the global plugins is a Kong responsibility
Marking a plugin with no_api is a plugin developer responsibility.
Those are different things.

@thibaultcha
Copy link
Member

The latest commit broke something, see the travis-ci build.

@subnetmarco subnetmarco force-pushed the feat/rewrite-by-lua branch from 12fb88a to 125f97f Compare April 11, 2017 20:55
@Tieske Tieske force-pushed the feat/rewrite-by-lua branch 2 times, most recently from d76ef57 to efef49e Compare April 25, 2017 12:32
@Tieske Tieske added this to the 0.10.2 milestone Apr 25, 2017
@Tieske
Copy link
Member

Tieske commented Apr 25, 2017

@thefosk @p0pr0ck5 @thibaultcha updated this as discussed. Now in the rewrite phase only the global plugins will be executed. Hence the rewrite handler of any plugin will only be executed if the plugin is configured as a global one.

Note: do not merge yet, would prefer to merge #2455 first and update this PR before merging (see TODO comments)

@Tieske Tieske force-pushed the feat/rewrite-by-lua branch from efef49e to 3a5f370 Compare April 26, 2017 06:30
@Tieske
Copy link
Member

Tieske commented Apr 26, 2017

update: fixed the update after 2455 was merged, so TODO comments are gone now

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.

Starting to look good to me! However, a few things in there are lacking, or unneeded...

end

function BasePlugin:log()
ngx.log(ngx.DEBUG, " executing plugin \""..self._name.."\": log")
ngx_log(DEBUG, "executing plugin \"", self._name, "\": log")
Copy link
Member

Choose a reason for hiding this comment

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

Sadly, these are some an unrelated change to this PR and should have been part of a different one...

end,
after = function ()
local ctx = ngx.ctx
ctx.KONG_REWRITE_TIME = get_now() - ctx.KONG_REWRITE_START -- time spent in Kong's rewrite_by_lua
Copy link
Member

Choose a reason for hiding this comment

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

This variable needs to be added to the basic log serializer when computing the latencies.kong property.

Copy link
Member

Choose a reason for hiding this comment

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

done!

@@ -180,6 +180,9 @@ return {

create_timer(PING_INTERVAL, ping_handler)
end,
rewrite = function()
-- Do nothing
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 don't think we need this? We manually call reports.init_worker() and reports.log(), but I see nowhere where reports.rewrite() is called. There is no reports.access() either, for example and for that matters.


describe("OpenResty handlers", function()

describe("rewrite on global plugin", function()
Copy link
Member

Choose a reason for hiding this comment

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

Would have been slightly better to have the sentences be slightly more specific when tests run with --o=gtest flag:

describe("OpenResty phases", function()
  describe("rewrite_by_lua", function()
    describe("enabled on all APIs", function()
      it("runs")
    end)
    describe("enabled on a specific APIs", function()
      it("doesn't run")
    end)
  end)
end)

reverted api-only config option. Rewrite handler will
only be executed on the globally configured plugins
@Tieske Tieske force-pushed the feat/rewrite-by-lua branch from 3a5f370 to 09659cb Compare April 27, 2017 22:32
thibaultcha pushed a commit that referenced this pull request Apr 28, 2017
Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>

This handler exposes the Nginx rewrite phase. This handler is called for
all loaded plugins (since the rewrite phase is executed prior to API
matching).

From #2354
@thibaultcha
Copy link
Member

Merged to release/0.10.2 for imminent release.

@thibaultcha thibaultcha deleted the feat/rewrite-by-lua branch April 28, 2017 08:12
thibaultcha pushed a commit that referenced this pull request Apr 29, 2017
Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>

This handler exposes the Nginx rewrite phase. This handler is called for
all loaded plugins (since the rewrite phase is executed prior to API
matching).

From #2354
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.

3 participants