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

plugins, runtime: Add visibility for server init #3706

Merged
merged 1 commit into from
Aug 12, 2021
Merged

plugins, runtime: Add visibility for server init #3706

merged 1 commit into from
Aug 12, 2021

Conversation

gshively11
Copy link
Contributor

  • Plugins can now access a channel which receives a message when the OPA
    server is fully initialized and ready to receive traffic.
  • Added ServerInitialized() and ServerInitializedChannel() to plugin
    manager.
  • Runtime now calls ServerInitialized() when server listeners are
    initialized.

Fixes #3701

(Tests will be implemented after review of implementation)

Signed-off-by: Grant Shively gshively@godaddy.com

plugins/plugins.go Outdated Show resolved Hide resolved
@gshively11
Copy link
Contributor Author

I confirmed this change resolves our problem.

@srenatus
Copy link
Contributor

srenatus commented Aug 4, 2021

Thank you! I'll have another look tomorrow.

Copy link
Contributor

@srenatus srenatus left a comment

Choose a reason for hiding this comment

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

I don't see any problems with that, but I'm not the most proficient when it comes to our plugin landscape... I guess added tests would help uncover potential problems -- that aside, it looks good to me. Thanks for spending time and thought here! 👍

runtime/runtime.go Show resolved Hide resolved
plugins/plugins.go Outdated Show resolved Hide resolved
@@ -441,6 +441,7 @@ func (rt *Runtime) Serve(ctx context.Context) error {
rt.serverInitMtx.Lock()
rt.serverInitialized = true
rt.serverInitMtx.Unlock()
rt.Manager.ServerInitialized()
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 there's a race condition here because there's no guarantee that the socket will have been opened.

The serverLoop() call on L430 (above) eventually calls down into net.Listen here and at that's what actually calls socket() and listen() at the OS level (so requests sent in the meantime will get network error.) That said, the window is extremely small; so perhaps that's fine. The solution would be to have this code wait until the server was actually listening for connections but that would require some more invasive changes to the listener interface (e.g., the serverLoop() function could return a channel or something to do indicate the listener was opened...)

@gshively11 if you agree w/ the above and are okay with the potential race condition, just include a comment here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, good catch. I think we're probably OK with this race condition, I'll add the comment. If it does end up being an issue, a modification as you described shouldn't be a breaking change, so it should be easy to implement if we need it.

@@ -340,6 +340,34 @@ func TestPluginManagerConsoleLogger(t *testing.T) {
}
}

func TestPluginManagerServerInitialized(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: It would be great if you could add a comment as to what you're trying to test in the 2 test cases below. It's not clear to me at least.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks, I somehow missed you weren't calling ServerInitialized() in the second case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I definitely was calling it lol, and it was passing because I was erroneously using return above it instead of break. So good catch 😁

Copy link
Member

@tsandall tsandall left a comment

Choose a reason for hiding this comment

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

LGTM. Just noticed one small future-proofing improvement on the manager change. @gshively11 if you add that in, we can merge this.

// ServerInitialized signals a channel indicating that the OPA
// server has finished initialization.
func (m *Manager) ServerInitialized() {
close(m.serverInitialized)
Copy link
Member

Choose a reason for hiding this comment

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

nit: Just realized that it would be easy to make this function idempotent. It's only ever being called once from inside of the runtime package but if someone else was instantiating the manager and somehow called this function twice, they would get a panic due to the channel already being closed. We could use a sync.Once primitive here?

- Plugins can now access a channel which receives a message when the OPA
  server is fully initialized and ready to receive traffic.
- Added ServerInitialized() and ServerInitializedChannel() to plugin
  manager.
- Runtime now calls ServerInitialized() when server listeners are
  initialized.

Fixes #3701

Signed-off-by: Grant Shively <gshively@godaddy.com>
@tsandall tsandall merged commit 6369788 into open-policy-agent:main Aug 12, 2021
@gshively11 gshively11 deleted the server-init-visibility branch August 12, 2021 21:32
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.

Proposal: Add visibility to OPA server initialization in Plugin Manager
4 participants