class Virtual
A controller which mananages several virtual hosts.
Spawns instances of Proxy
and Redirect
to handle incoming requests.
A virtual host is an application bound to a specific authority (essentially a hostname). The virtual controller manages multiple hosts and allows a single server to host multiple applications easily.
Definitions
def assume_privileges(path)
Drop privileges according to the user and group of the specified path.
Signature
-
parameter
path
String
The path to the application directory.
-
returns
Hash
The environment to use for the spawned process.
Implementation
def assume_privileges(path)
# Process.exec / Process.spawn don't replace the environment but instead update it, so we need to clear out any existing BUNDLE_ variables using `nil` values, which will cause them to be removed from the child environment:
env = ENV.to_h do |key, value|
if key.start_with?("BUNDLE_")
[key, nil]
else
[key, value]
end
end
env["PWD"] = File.dirname(path)
stat = File.stat(path)
Process::GID.change_privilege(stat.gid)
Process::UID.change_privilege(stat.uid)
home = Etc.getpwuid(stat.uid).dir
env["HOME"] = home
return env
end
def spawn(path, container, **options)
Spawn an application instance from the specified path.
Signature
-
parameter
path
String
The path to the application directory.
-
parameter
container
Async::Container::Generic
The container to spawn into.
-
parameter
options
Options
The options which are passed to
exec
.
Implementation
def spawn(path, container, **options)
container.spawn(name: "Falcon Application", restart: true, key: path) do |instance|
env = assume_privileges(path)
instance.exec(env, "bundle", "exec", path, ready: false, **options)
end
end
def setup(container)
Setup the container with Redirect
and Proxy
child processes.
These processes are gracefully restarted if they are already running.
Signature
-
parameter
container
Async::Container::Generic
Implementation
def setup(container)
if proxy = container[:proxy]
proxy.kill(:HUP)
end
if redirect = container[:redirect]
redirect.kill(:HUP)
end
container.reload do
evaluator = @environment.evaluator
falcon_path = evaluator.falcon_path
Console.info(self, "Loading configurations:", paths: evaluator.resolved_configuration_paths)
evaluator.resolved_configuration_paths.each do |path|
path = File.expand_path(path)
root = File.dirname(path)
spawn(path, container, chdir: root)
end
container.spawn(name: "Falcon Redirector", restart: true, key: :redirect) do |instance|
instance.exec(falcon_path, "redirect",
"--bind", evaluator.bind_insecure,
"--timeout", evaluator.timeout.to_s,
"--redirect", evaluator.bind_secure,
*evaluator.configuration_paths, ready: false
)
end
container.spawn(name: "Falcon Proxy", restart: true, key: :proxy) do |instance|
instance.exec(falcon_path, "proxy",
"--bind", evaluator.bind_secure,
"--timeout", evaluator.timeout.to_s,
*evaluator.configuration_paths, ready: false
)
end
end
end