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: Add SSL support for http api servers via bentoml serve #2886

Merged
merged 4 commits into from
Aug 12, 2022

Conversation

sptowey
Copy link
Contributor

@sptowey sptowey commented Aug 9, 2022

What does this PR address?

Before submitting:

Who can help review?

@ssheng
@sauyon

Feel free to tag members/contributors who can help review your PR.

@sptowey sptowey requested review from ssheng, parano and a team as code owners August 9, 2022 21:23
@sptowey sptowey requested review from sauyon and removed request for a team August 9, 2022 21:23
@pep8speaks
Copy link

pep8speaks commented Aug 9, 2022

Hello @sptowey, Thanks for updating this PR.

There are currently no PEP 8 issues detected in this PR. Cheers! 🍻

Comment last updated at 2022-08-11 19:51:29 UTC

Copy link
Contributor

@aarnphm aarnphm left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution. Make sure to run make format and make lint locally 🎉

bentoml/_internal/configuration/containers.py Show resolved Hide resolved
bentoml/serve.py Outdated
Comment on lines 87 to 93
ssl_keyfile: t.Optional[str] = None,
ssl_certfile: t.Optional[str] = None,
ssl_keyfile_password: t.Optional[str] = None,
ssl_version: t.Optional[int] = None,
ssl_cert_reqs: t.Optional[int] = None,
ssl_ca_certs: t.Optional[str] = None,
ssl_ciphers: t.Optional[str] = None,
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 use dependency injection here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1. Let's inject config here.

ssl_keyfile: t.Optional[str] = Provide[BentoMLContainer.api_server_config.ssl.keyfile]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aha, I understand now. I'd considered doing it that was to start, but wasn't entirely clear on if Provide would default to None as expected.

"--ssl-keyfile",
type=click.STRING,
help="SSL key file",
default=None,
Copy link
Member

Choose a reason for hiding this comment

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

Should we set the default value from config here? e.g.

        default=BentoMLContainer.api_server_config.ssl.keyfile.get(),

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 we should use dependency injection like Aaron said above, we probably should try to start avoiding depending on BentoML before the click initialization so that click completion isn't horribly slow.

Copy link
Contributor

Choose a reason for hiding this comment

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

After this PR got merge, I think we can do a quick cleanup on CLI and set default value to None, and then we can access the value via DI lazily.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know if you want me to help out with this. Sounds like you all may have it under control though?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Since there is no default value for the SSL related configurations, doing dependency injection here is not very meaningful. I think we can leave it out.

Copy link
Contributor

Choose a reason for hiding this comment

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

It is more about user providing this option via config right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Correct. What I meant was that we should do config injection at the places you suggested in serve_development and serve_production instead of CLI.

@codecov
Copy link

codecov bot commented Aug 10, 2022

Codecov Report

Merging #2886 (9fbcba4) into main (ce6342d) will increase coverage by 0.14%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2886      +/-   ##
==========================================
+ Coverage   70.70%   70.85%   +0.14%     
==========================================
  Files         103      103              
  Lines        9302     9328      +26     
==========================================
+ Hits         6577     6609      +32     
+ Misses       2725     2719       -6     
Impacted Files Coverage Δ
bentoml/_internal/configuration/containers.py 80.70% <ø> (ø)
bentoml/_internal/utils/docker.py 68.96% <0.00%> (-4.95%) ⬇️
bentoml/_internal/yatai_client/__init__.py 25.00% <0.00%> (-0.51%) ⬇️
bentoml/_internal/runner/runnable.py 93.75% <0.00%> (+1.56%) ⬆️
bentoml/_internal/utils/analytics/usage_stats.py 96.42% <0.00%> (+18.81%) ⬆️

@sptowey
Copy link
Contributor Author

sptowey commented Aug 10, 2022

Thanks for the contribution. Make sure to run make format and make lint locally 🎉

Whoops, I ran the linter but missed the formatter!

"--ssl-keyfile",
type=click.STRING,
help="SSL key file",
default=None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Correct. What I meant was that we should do config injection at the places you suggested in serve_development and serve_production instead of CLI.

bentoml/serve.py Outdated
Comment on lines 87 to 93
ssl_keyfile: t.Optional[str] = None,
ssl_certfile: t.Optional[str] = None,
ssl_keyfile_password: t.Optional[str] = None,
ssl_version: t.Optional[int] = None,
ssl_cert_reqs: t.Optional[int] = None,
ssl_ca_certs: t.Optional[str] = None,
ssl_ciphers: t.Optional[str] = None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

+1. Let's inject config here.

ssl_keyfile: t.Optional[str] = Provide[BentoMLContainer.api_server_config.ssl.keyfile]

bentoml/serve.py Outdated
Comment on lines 212 to 218
ssl_keyfile: t.Optional[str] = None,
ssl_certfile: t.Optional[str] = None,
ssl_keyfile_password: t.Optional[str] = None,
ssl_version: t.Optional[int] = None,
ssl_cert_reqs: t.Optional[int] = None,
ssl_ca_certs: t.Optional[str] = None,
ssl_ciphers: t.Optional[str] = None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

And inject config here.

ssl_keyfile: t.Optional[str] = Provide[BentoMLContainer.api_server_config.ssl.keyfile],

Comment on lines +373 to +393
api_server_watcher_args.extend(
["--ssl-keyfile", ssl_keyfile]
) if ssl_keyfile is not None else None # pylint: disable=W0106
api_server_watcher_args.extend(
["--ssl-certfile", ssl_certfile]
) if ssl_certfile is not None else None # pylint: disable=W0106
api_server_watcher_args.extend(
["--ssl-keyfile-password", ssl_keyfile_password]
) if ssl_keyfile_password is not None else None # pylint: disable=W0106
api_server_watcher_args.extend(
["--ssl-version", str(ssl_version)]
) if ssl_version is not None else None # pylint: disable=W0106
api_server_watcher_args.extend(
["--ssl-cert-reqs", str(ssl_cert_reqs)]
) if ssl_cert_reqs is not None else None # pylint: disable=W0106
api_server_watcher_args.extend(
["--ssl-ca-certs", ssl_ca_certs]
) if ssl_ca_certs is not None else None # pylint: disable=W0106
api_server_watcher_args.extend(
["--ssl-ciphers", ssl_ciphers]
) if ssl_ciphers is not None else None # pylint: disable=W0106
Copy link
Contributor

Choose a reason for hiding this comment

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

https://github.com/encode/uvicorn/blob/b21ecabc5bf911f571e0629438315a1e5472065c/uvicorn/config.py

Uvicorn does handle None option for some option.

IMO, a nicer way to write None check is

if ssl_certfile:
   args.extend(["--ssl-certfile", ssl_certfile])
if ssl_cert_reqs:
   args.extend(...)
if ssl_version:
   ...

Then we can pass all of the other options straight through

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, this is a weird bit of code. It doesn't (shouldn't?) actually pass None into uvicorn - here is where uvicorn actually gets the args if they exist.
I wrote it this way to try compacting the code a bit, but running it through the formatter made that a moot point. I agree that it should be reformatted to the way you proposed - much easier to understand.

Copy link
Contributor

@aarnphm aarnphm left a comment

Choose a reason for hiding this comment

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

Thanks again for the contribution. I can update the style with a follow-up PR.

@ssheng ssheng merged commit a48d83e into bentoml:main Aug 12, 2022
aarnphm pushed a commit that referenced this pull request Aug 14, 2022
* Passthrough SSL args from "bentoml server" to uvicorn api servers

Supress pylint warning

* Delete TODO comments

* Fix code formatting

* Inject ssl defaults from config

Signed-off-by: Aaron Pham <[email protected]>
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.

6 participants