server: run neutron-api under Apache

According to
https://docs.openstack.org/neutron/wallaby/admin/config-wsgi.html
it is entirely okay to have Apache handle the Neutron API. Do so,
it makes it easier to both keep services under control and change
SSL settings.

Strongly inspired by implementation of same in openstack-block-storage
and openstack-compute. First iteration, without test updates.

PS. Prior to this change this cookbook did NOT in fact properly manage
Neutron on modern Debian - it appears to assume running as an old-style,
monolithic server yet at least Buster only provides scripts for running
neutron-api as a standalone UWSGI app + neutron-rpc-server separately.
This means that those services only ran because dpkg told them to
at install time.

Signed-off-by: Marek Szuba <m.szuba@gsi.de>
Change-Id: I02f777956adb332185a6e47a32e253970293edc4
This commit is contained in:
Marek Szuba 2021-09-07 10:55:51 +01:00
parent 222df62ab3
commit f6ba8760d4
5 changed files with 126 additions and 13 deletions

View File

@ -33,6 +33,19 @@ end
default['openstack']['bind_service']['all']['network']['host'] = '127.0.0.1'
default['openstack']['bind_service']['all']['network']['port'] = 9696
# SSL settings for neutron-api
default['openstack']['network']['ssl']['enabled'] = false
default['openstack']['network']['ssl']['certfile'] = ''
default['openstack']['network']['ssl']['chainfile'] = ''
default['openstack']['network']['ssl']['keyfile'] = ''
default['openstack']['network']['ssl']['ca_certs_path'] = ''
default['openstack']['network']['ssl']['cert_required'] = false
default['openstack']['network']['ssl']['protocol'] = ''
default['openstack']['network']['ssl']['ciphers'] = ''
default['openstack']['network']['processes'] = 2
default['openstack']['network']['threads'] = 10
# trigger the usage of syslog (will include the proper recipe to create a log
# config)
default['openstack']['network']['syslog']['use'] = false
@ -165,7 +178,7 @@ default['openstack']['network']['platform'].tap do |platform|
platform['neutron_linuxbridge_agent_service'] = 'neutron-linuxbridge-agent'
platform['neutron_metadata_agent_packages'] = []
platform['neutron_metering_agent_packages'] = %w(openstack-neutron-metering-agent)
platform['neutron_server_packages'] = []
platform['neutron_server_packages'] = %w(mod_wsgi)
platform['neutron_openvswitch_service'] = 'openvswitch'
platform['neutron_openvswitch_agent_service'] = 'neutron-openvswitch-agent'
platform['package_overrides'] = ''
@ -199,7 +212,7 @@ default['openstack']['network']['platform'].tap do |platform|
platform['neutron_linuxbridge_agent_service'] = 'neutron-linuxbridge-agent'
platform['neutron_metadata_agent_packages'] = %w(neutron-metadata-agent)
platform['neutron_metering_agent_packages'] = %w(neutron-metering-agent)
platform['neutron_server_packages'] = %w(neutron-server)
platform['neutron_server_packages'] = %w(libapache2-mod-wsgi-py3 neutron-server)
platform['neutron_openvswitch_service'] = 'openvswitch-switch'
platform['neutron_openvswitch_agent_service'] = 'neutron-openvswitch-agent'
platform['package_overrides'] = ''

View File

@ -9,6 +9,7 @@ version '20.0.0'
supports os
end
depends 'apache2', '~> 8.1'
depends 'openstackclient'
depends 'openstack-common', '>= 20.0.0'
depends 'openstack-identity', '>= 20.0.0'

View File

@ -96,6 +96,22 @@ end
# merge all config options and secrets to be used in the neutron.conf.erb
neutron_conf_options = merge_config_options 'network'
plugin_templates = []
node['openstack']['network']['plugins'].each_value.to_s do |plugin|
plugin_templates << "template[#{File.join(plugin['path'], plugin['filename'])}]"
end
# service['apache2'] is defined in the apache2_default_install resource
# but other resources are currently unable to reference it. To work
# around this issue, define the following helper in your cookbook:
service 'apache2' do
extend Apache2::Cookbook::Helpers
service_name lazy { apache_platform_service_name }
supports restart: true, status: true, reload: true
action :nothing
subscribes :restart, plugin_templates
end
template '/etc/neutron/neutron.conf' do
source 'openstack-service.conf.erb'
cookbook 'openstack-common'
@ -106,6 +122,7 @@ template '/etc/neutron/neutron.conf' do
variables(
service_config: neutron_conf_options
)
notifies :restart, 'service[apache2]'
end
# delete all secrets saved in the attribute

View File

@ -21,9 +21,9 @@
include_recipe 'openstack-network'
# Make Openstack object available in Chef::Recipe
class ::Chef::Recipe
include ::Openstack
include Apache2::Cookbook::Helpers
end
template '/etc/default/neutron-server' do
@ -56,25 +56,71 @@ if node['openstack']['network']['policyfile_url']
owner node['openstack']['network']['platform']['user']
group node['openstack']['network']['platform']['group']
mode '644'
notifies :restart, 'service[apache2]', :immediately
end
end
# Migrate network database to latest version
include_recipe 'openstack-network::db_migration'
plugin_templates = []
node['openstack']['network']['plugins'].each_value.to_s do |plugin|
plugin_templates << "template[#{File.join(plugin['path'], plugin['filename'])}]"
end
# Disable standalone service to make room for Apache
service 'neutron-server' do
service_name platform_options['neutron_server_service']
supports status: true, restart: true
action [:disable, :stop]
end
# When Neutron API is served by a Web server it is difficult for it to start
# an RPC listener thread, therefore start the RPC server as a separate service.
service 'neutron-rpc-server' do
service_name platform_options['neutron_rpc_server_service']
action [:enable, :start]
subscribes :restart, [
plugin_templates,
'template[/etc/neutron/neutron.conf]',
'remote_file[/etc/neutron/policy.json]',
].flatten
end
bind_service = node['openstack']['bind_service']['all']['network']
# Finds and appends the listen port to the apache2_install[openstack]
# resource which is defined in openstack-identity::server-apache.
apache_resource = find_resource(:apache2_install, 'openstack')
if apache_resource
apache_resource.listen = [apache_resource.listen, "#{bind_service['host']}:#{bind_service['port']}"].flatten
else
apache2_install 'openstack' do
listen "#{bind_service['host']}:#{bind_service['port']}"
end
end
apache2_module 'wsgi'
apache2_module 'ssl' if node['openstack']['network']['ssl']['enabled']
template "#{apache_dir}/sites-available/neutron-api.conf" do
extend Apache2::Cookbook::Helpers
source 'wsgi-template.conf.erb'
variables(
daemon_process: 'neutron-api',
server_host: bind_service['host'],
server_port: bind_service['port'],
server_entry: '/usr/bin/neutron-api',
log_dir: default_log_dir,
run_dir: lock_dir,
user: node['openstack']['network']['platform']['user'],
group: node['openstack']['network']['platform']['group'],
processes: node['openstack']['network']['processes'],
threads: node['openstack']['network']['threads'],
use_ssl: node['openstack']['network']['ssl']['enabled'],
cert_file: node['openstack']['network']['ssl']['certfile'],
chain_file: node['openstack']['network']['ssl']['chainfile'],
key_file: node['openstack']['network']['ssl']['keyfile'],
ca_certs_path: node['openstack']['network']['ssl']['ca_certs_path'],
cert_required: node['openstack']['network']['ssl']['cert_required'],
protocol: node['openstack']['network']['ssl']['protocol'],
ciphers: node['openstack']['network']['ssl']['ciphers']
)
notifies :restart, 'service[apache2]'
end
apache2_site 'neutron-api' do
notifies :restart, 'service[apache2]', :immediately
end
include_recipe 'openstack-network::identity_registration'

View File

@ -0,0 +1,36 @@
<%= node['openstack']['network']['custom_template_banner'] %>
<VirtualHost <%= @server_host %>:<%= @server_port %>>
WSGIDaemonProcess <%= @daemon_process %> processes=<%= @processes %> threads=<%= @threads %> user=<%= @user %> group=<%= @group %> display-name=%{GROUP}
WSGIProcessGroup <%= @daemon_process %>
WSGIScriptAlias / <%= @server_entry %>
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
<Directory /usr/bin>
Require all granted
</Directory>
ErrorLogFormat "%{cu}t %M"
ErrorLog <%= @log_dir %>/<%= @daemon_process %>_error.log
CustomLog <%= @log_dir %>/<%= @daemon_process %>_access.log combined
<% if @use_ssl -%>
SSLEngine On
SSLCertificateFile <%= @cert_file %>
SSLCertificateKeyFile <%= @key_file %>
SSLCACertificatePath <%= @ca_certs_path %>
<% unless @chain_file.empty? %>
SSLCertificateChainFile <%= @chain_file %>
<% end -%>
SSLProtocol <%= @protocol %>
<% unless @ciphers.empty? -%>
SSLCipherSuite <%= @ciphers %>
<% end -%>
<% if @cert_required -%>
SSLVerifyClient require
<% end -%>
<% end -%>
</VirtualHost>
WSGISocketPrefix <%= @run_dir -%>