Skip to content

Conversation

@ik5
Copy link

@ik5 ik5 commented Oct 14, 2018

Work in progress (still did not test it or wrote any tests for it), loading puma (or) webrick as an HTTP Server.

Started earlier today to work on it, most of it done, but not all :)

lib/launcher.rb Outdated

RACK_SERVERS = {
:webrick => Rack::Handler::WEBrick,
:puma => Rack::Handler::Puma
Copy link
Member

Choose a reason for hiding this comment

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

won't this will require both gems to load? e.g. if you dont have puma gem, this line will break?

Copy link
Member

Choose a reason for hiding this comment

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

Does it hurt to load them both? If it don't let's ignore it? If it does, then let's definitely take care of this.

Copy link
Member

Choose a reason for hiding this comment

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

So it looks like webrick is always present, dependency of sinatra or something. But we should be able to install foreman-proxy without puma bundler group, so this needs to be taken care of.

@ik5
Copy link
Author

ik5 commented Oct 14, 2018 via email

lib/launcher.rb Outdated
{
:app => app,
:server => :webrick,
:server => Proxy::SETTINGS.http_server_type || :webrick,
Copy link
Member

Choose a reason for hiding this comment

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

This does not correspondend with the line above :server => Proxy::SETTINGS.http_server_type.to_sym, so either one or another. The settings stack handles the defaults, so I think the version from 58 is better.

@@ -0,0 +1 @@
gem 'puma', '3.11.4'
Copy link
Member

Choose a reason for hiding this comment

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

This should be in group :puma so users can turn it on or off via bundler. In RPM deployments, we need to do packaging change and do subpackage so installing foreman-proxy-puma will actually grab the dependency. Also I'd probably add '~> 3.11' requirement, not sure about the gemspec syntax tho.

@lzap
Copy link
Member

lzap commented Oct 15, 2018

Nicely done, if it boots up and can be properly disabled without the puma dependency, let's ship it to hear from our users after 1.20 is branched. We can test it many times, but only our community will really tell us.

@ik5
Copy link
Author

ik5 commented Oct 15, 2018

there are basics puma, but it does not handle the actual execution for the route properly, and still on it, and when that works, I will have to do two things:

A. Fix tests
B. Add tests for Puma
C. Group Puma, and only if it exists load things that belongs to it.

@iNecas
Copy link
Member

iNecas commented Oct 16, 2018

Also, ssl doesn't work at all yet

@ik5
Copy link
Author

ik5 commented Oct 16, 2018

Also, ssl doesn't work at all yet

I haven't tested it yet, because the actual routing crashes, and now working on that part.

gem 'puma', '3.11.4', :require => 'puma'
else
gem 'puma', :require => 'puma'
end
Copy link
Member

Choose a reason for hiding this comment

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

Holy Moly, we are lucky that 3.11 was the last version supporting Ruby 2.0. Latest is 3.12 which only supports Ruby 2.2+. Unfortunately, SCLing proxy is imminent.

Can you avoid open-ended version requirement on line 5? Packagers will require us to have a specific version, something like '~> 3.12' or something like that.

gem 'pry'
gem 'pry-rescue'
gem 'pry-stack_explorer'
gem 'pry-byebug'
Copy link
Member

Choose a reason for hiding this comment

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

These belong to bundler.d/Gemfile.local.rb

Copy link
Author

Choose a reason for hiding this comment

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

ack, I thought it can help debug on development, but np :)

Copy link
Member

Choose a reason for hiding this comment

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

It can, we tend to be little more strict in core, I'd probably follow this rule. Everyone use her own tools.

end

require 'puma'
Puma::Server.class_eval { include PumaPatch }
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 like monkey patching just because of one or two simple calls. In the method where you call mount you already have case server_name anyway, I suggest to do the mapping there, or in a launcher helper.

Copy link
Author

Choose a reason for hiding this comment

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

ack

lib/launcher.rb Outdated
require 'webrick'
begin
require 'puma'
Bundler.require(:puma)
Copy link
Member

Choose a reason for hiding this comment

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

Please test this on RPM installation, I think this will not work. We actually turn bundler off for RPM installations and use special stub called bundler_ext so it works seamlessly with Bundler for development.

Copy link
Author

Choose a reason for hiding this comment

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

Will check it out at the end of my work (soon, very soon :) )

lib/launcher.rb Outdated
https_server_name = @settings.https_server_type
if https_app
t1 = case https_server_name
when :webrick
Copy link
Member

Choose a reason for hiding this comment

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

I would extract this to a method add_server() then then calls add_webrick_server or add_puma_server to reduce the duplication.

Copy link
Author

Choose a reason for hiding this comment

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

executing the server is blocking, so at the moment actually playing around with my threading design.

the need for it, is to support multiple hosts, that the current way of working as a server (puma that is) is blocking.

@ik5
Copy link
Author

ik5 commented Oct 21, 2018

Okay, almost there, now working on making SSL/TLS to work.

Important thing, after investing a lot of time testing it out, I can't bind to many hosts per port, only for a single one.
The reason is that I will require to manage multiple threads - one per host and port/connection type. The reason for it, is that each server running entry is block instead of non-block.
In order to manage multiple hosts/connection type, there is a need to manage a threadpool and other resources management system.

I think that as another task, such management can be written,

@ik5
Copy link
Author

ik5 commented Oct 23, 2018

Several notes:

A. Last working version of Puma with Ruby v2.0.0 is 3.10.0 (puma/puma#1662).
B. Puma's version of 3.10.0 does not support of filtering Ciphers in any way (so no code for that).
C. Currently fixing some tests, Ruby 2.0.0 have bug with Kerberos that makes it crash with the tests, so handpicking the tests and testing them.

Once the tests are ready I'll remove the WIP part.
@lzap now it's more or less ready for PR review regarding the sources of the logic without much of rewrites :)

@@ -0,0 +1,11 @@

class PumaMapperMiddleware
def initialize(app)
Copy link
Member

Choose a reason for hiding this comment

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

Is this middleware needed for anything right now?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, it is the only way for Puma to enter the route and deal with it.

Copy link
Author

Choose a reason for hiding this comment

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

there is another way of doing it, but then we will ignore rack, and that by using add_xxx_listener (for example) of Puma, but we can then support multiple Ethernet devices, and that's the balance I was playing with.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I don't get it. The only place this middleware is being used is in here https://github.com/theforeman/smart-proxy/pull/613/files#diff-b8fbcbffabe3ae5c9935bb21e3e94852R178, and I don't see the server variable being used anywhere.

@settings = settings
@settings.http_server_type = Proxy::SETTINGS.http_server_type.to_sym
@settings.https_server_type = Proxy::SETTINGS.https_server_type.to_sym
if @settings.http_server_type == :puma && !$HAS_PUMA
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 an extra $GLOBAL_VARIABLE, we can just check on defined? Puma

Copy link
Author

Choose a reason for hiding this comment

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

my issue with define puma is that if something else regarding puma was not loaded we do not know of it, and then looking for every point that is needed is a bit of an issue in my opinion.

You will end up either writing a function that does this, or have duplicate places that check that code.

So knowing that everything was loaded properly, even on other locations at the project when needed is a bit easier in my opinion and easier for the long run.

lib/launcher.rb Outdated
require 'thread'
require 'rack'
require 'webrick'
require 'pry'
Copy link
Member

Choose a reason for hiding this comment

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

still a leftover from requiring pry for development

Copy link
Author

Choose a reason for hiding this comment

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

that's my bad, I added it when debug puma crashes, removing it

require 'proxy/signal_handler'
require 'thread'
require 'rack'
require 'webrick'
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to require webrick in case we will not use it?

Copy link
Author

Choose a reason for hiding this comment

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

if the loading of puma failed it is the fallback, and at the moment the SETTINGS constant is not available for me to know if to load it or not.

Do you have a better idea?

Copy link
Member

Choose a reason for hiding this comment

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

What about loading webrick or puma just after we know what server we're going to use? We don't have to load everything at the very beginning, if we have a reason for that. That would also allow us not to use the $HAS_PUMA global variable

# https server type configuration
# A string that indicates the server type (possible values: 'webrick', 'puma').
# Default value is 'webrick'
#:https_server_type: 'puma'
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 really need separate server_type setting for http and https and I think it's just misleading. One option should rule them all

Copy link
Author

Choose a reason for hiding this comment

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

okay unifying them

@iNecas
Copy link
Member

iNecas commented Oct 23, 2018

When running via bundle exec bin/smart-proxy, I can't quit the process with CTRL+C, when running without bundle exec it fails with LoadError: cannot load such file -- puma. I think at least one of the variants should work

@ik5
Copy link
Author

ik5 commented Oct 24, 2018

@iNecas the pressing of ^C works for me, the only time it didn't was when i was inside a breakpoint.

screenshot at 2018-10-24 09-26-06

@ik5 ik5 changed the title [WIP] Puma support for smart proxy Fixes #25293 - Puma support for smart proxy Oct 24, 2018
@ik5
Copy link
Author

ik5 commented Oct 24, 2018

fixed all known test issues (ruby 2.0.0 crashes on a bug of kerberos), so using the following test mechanism to test my code :)

@theforeman-bot
Copy link
Member

There were the following issues with the commit message:

  • e1e7373 must be in the format fixes #redmine_number - brief description
  • commit message for e1e7373 is not wrapped at 72nd column
  • commit message for e1e7373 is not wrapped at 72nd column

If you don't have a ticket number, please create an issue in Redmine.

More guidelines are available in Coding Standards or on the Foreman wiki.


This message was auto-generated by Foreman's prprocessor

@iNecas
Copy link
Member

iNecas commented Oct 24, 2018

Interesting regarding the ^C behavior: can you check with ruby 2.4 and 2.5 (2.4.1 and 2.5.1 were misbehaving with ^C for me)

@lzap
Copy link
Member

lzap commented Oct 24, 2018

That sounds more like a race condition than a problem with a particular Ruby version.

Anyway, what is the status of the PR? Is this still WIP? I want to do formal review and testing after it's finished.

when :puma
Thread.new do
add_puma_server(app, addresses, port, conn_type)
end
Copy link
Member

Choose a reason for hiding this comment

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

Any particular reason why the two blocks don't have the same syntax (do vs {)?

Copy link
Author

Choose a reason for hiding this comment

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

originally there was a longer line and wanted to make it readable, use moved to do instead of proc.

@lzap
Copy link
Member

lzap commented Oct 24, 2018

I think the way we handle UNIX signals is incorrect in the current version, we kinda do this (signal_handler.rb):

trap(:INT) { exit(0) }
trap(:TERM) { exit(0) }

We should change that and do graceful shutdown. Puma server has methods for graceful stop for both Single and Cluster classes called stop_blocked. We should also correct this for webrick which offers method called shutdown. There is no need of checking a timelimit, systemd will kill the process if it takes too long (45 secs by default) to gracefully terminate.

@lzap
Copy link
Member

lzap commented Oct 24, 2018

To be able to do that, you'd probably need to use ::Puma::Launcher instead of ::Rack::Handler::Puma wrapper.

@ik5
Copy link
Author

ik5 commented Nov 4, 2018

@lzap Puma has it's own handler for the signals: https://github.com/puma/puma/blob/v3.10.0/lib/rack/handler/puma.rb#L70

And as you can see at that file, it is using launcher.

@lzap
Copy link
Member

lzap commented Nov 9, 2018

Interrupt Ruby exception is only for Ctrl-C interrupt for interactive mode. In production you run this as a daemon but it still needs to be able to respond to SIGTERM or SIGHUP and SIGUSR1. We use these to rotate logs and initiate graceful restart. So this is different thing, that's why I suggest to change how things are booted up.

Anyway, what is the status? This is entitled WIP, so wondering what are the plans and timeframe. I like your work, would totally love to see this happening.

@ik5
Copy link
Author

ik5 commented Nov 12, 2018

@lzap, the status is that I waited for your comments.
I'm not sure that it is WIP anymore, but I will add what you have commented here.

@ik5 ik5 closed this Nov 15, 2018
@ik5 ik5 deleted the devel/puma branch November 15, 2018 06:41
@lzap
Copy link
Member

lzap commented Nov 19, 2018

Sorry I haven't noticed you already removed the WIP tag, I would like to proceed with testing but it appears you closed the PR and deleted the branch?

@lzap
Copy link
Member

lzap commented Nov 19, 2018

I opened new PR at #623 with your commit, I will push it through. @iNecas want to take a look?

@ik5
Copy link
Author

ik5 commented Nov 19, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants