diff --git a/Berksfile b/Berksfile index 91e3850..0a71871 100644 --- a/Berksfile +++ b/Berksfile @@ -1,6 +1,18 @@ source 'https://supermarket.chef.io' -%w(client -image -identity -common).each do |cookbook| +solver :ruby, :required + +%w( + client + -common + -dns + -identity + -image + -integration-test + -network + -ops-database + -ops-messaging +).each do |cookbook| if Dir.exist?("../cookbook-openstack#{cookbook}") cookbook "openstack#{cookbook}", path: "../cookbook-openstack#{cookbook}" else diff --git a/README.rst b/README.rst index df83c80..19d94ab 100644 --- a/README.rst +++ b/README.rst @@ -36,13 +36,12 @@ Cookbooks The following cookbooks are dependencies: -- 'apache2', '5.0.1' +- 'apache2', '~> 8.0' - 'lvm' - 'openstackclient' - 'openstack-common', '>= 18.0.0' - 'openstack-identity', '>= 18.0.0' - 'openstack-image', '>= 18.0.0' -- 'selinux' Attributes ========== diff --git a/attributes/default.rb b/attributes/default.rb index 95566a7..91f8dfa 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -87,7 +87,7 @@ when 'rhel' # :pragma-foodcritic: ~FC024 - won't fix this default['openstack']['block-storage']['volume']['iscsi_helper'] = 'lioadm' default['openstack']['block-storage']['platform'] = { 'cinder_common_packages' => ['openstack-cinder'], - 'cinder_api_packages' => ['openstack-cinder'], + 'cinder_api_packages' => ['openstack-cinder', 'mod_wsgi'], 'cinder_api_service' => 'openstack-cinder-api', 'cinder_volume_packages' => ['qemu-img-ev'], 'cinder_volume_service' => 'openstack-cinder-volume', diff --git a/metadata.rb b/metadata.rb index 1339e37..67316e6 100644 --- a/metadata.rb +++ b/metadata.rb @@ -17,14 +17,12 @@ recipe 'volume', 'Installs the cinder-volume service' supports os end +depends 'apache2', '~> 8.0' +depends 'lvm' +depends 'openstackclient' depends 'openstack-common', '>= 18.0.0' depends 'openstack-identity', '>= 18.0.0' depends 'openstack-image', '>= 18.0.0' -depends 'openstackclient' - -depends 'apache2', '5.0.1' -depends 'lvm' -depends 'selinux' issues_url 'https://launchpad.net/openstack-chef' source_url 'https://opendev.org/openstack/cookbook-openstack-block-storage' diff --git a/recipes/api.rb b/recipes/api.rb index 855002e..a6f822f 100644 --- a/recipes/api.rb +++ b/recipes/api.rb @@ -23,6 +23,7 @@ # Make Openstack object available in Chef::Recipe class ::Chef::Recipe include ::Openstack + include Apache2::Cookbook::Helpers end include_recipe 'openstack-block-storage::cinder-common' @@ -68,43 +69,42 @@ if node['openstack']['block-storage']['policyfile_url'] end end +# 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']['block-storage']['ssl']['enabled'] + # remove the cinder-wsgi.conf automatically generated from package -apache_config 'cinder-wsgi' do - enable false +apache2_conf 'cinder-wsgi' do + action :disable end -web_app 'cinder-api' do - template 'wsgi-template.conf.erb' - daemon_process 'cinder-wsgi' - server_host bind_service['host'] - server_port bind_service['port'] - server_entry '/usr/bin/cinder-wsgi' - log_dir node['apache']['log_dir'] - run_dir node['apache']['run_dir'] - user node['openstack']['block-storage']['user'] - group node['openstack']['block-storage']['group'] - use_ssl node['openstack']['block-storage']['ssl']['enabled'] - cert_file node['openstack']['block-storage']['ssl']['certfile'] - chain_file node['openstack']['block-storage']['ssl']['chainfile'] - key_file node['openstack']['block-storage']['ssl']['keyfile'] - ca_certs_path node['openstack']['block-storage']['ssl']['ca_certs_path'] - cert_required node['openstack']['block-storage']['ssl']['cert_required'] - protocol node['openstack']['block-storage']['ssl']['protocol'] - ciphers node['openstack']['block-storage']['ssl']['ciphers'] +template "#{apache_dir}/sites-available/cinder-api.conf" do + extend Apache2::Cookbook::Helpers + source 'wsgi-template.conf.erb' + variables( + daemon_process: 'cinder-wsgi', + server_host: bind_service['host'], + server_port: bind_service['port'], + server_entry: '/usr/bin/cinder-wsgi', + log_dir: default_log_dir, + run_dir: lock_dir, + user: node['openstack']['block-storage']['user'], + group: node['openstack']['block-storage']['group'] + ) + notifies :restart, 'service[apache2]' end -# Hack until Apache cookbook has lwrp's for proper use of notify restart -# apache2 after keystone if completely configured. Whenever a cinder -# config is updated, have it notify the resource which clears the lock -# so the service can be restarted. -# TODO(ramereth): This should be removed once this cookbook is updated -# to use the newer apache2 cookbook which uses proper resources. -edit_resource(:template, "#{node['apache']['dir']}/sites-available/cinder-api.conf") do - notifies :run, 'execute[Clear cinder-api apache restart]', :immediately -end - -execute 'cinder-api apache restart' do - command "touch #{Chef::Config[:file_cache_path]}/cinder-api-apache-restarted" - creates "#{Chef::Config[:file_cache_path]}/cinder-api-apache-restarted" +apache2_site 'cinder-api' do notifies :restart, 'service[apache2]', :immediately end diff --git a/recipes/cinder-common.rb b/recipes/cinder-common.rb index 94acd90..9383c7c 100644 --- a/recipes/cinder-common.rb +++ b/recipes/cinder-common.rb @@ -83,8 +83,13 @@ end # merge all config options and secrets to be used in the cinder.conf.erb cinder_conf_options = merge_config_options 'block-storage' -execute 'Clear cinder-api apache restart' do - command "rm -f #{Chef::Config[:file_cache_path]}/cinder-api-apache-restarted" +# 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 end @@ -97,7 +102,7 @@ template '/etc/cinder/cinder.conf' do variables( service_config: cinder_conf_options ) - notifies :run, 'execute[Clear cinder-api apache restart]', :immediately + notifies :restart, 'service[apache2]' end # delete all secrets saved in the attribute diff --git a/spec/api-redhat_spec.rb b/spec/api-redhat_spec.rb index cb6b7a1..221eee5 100644 --- a/spec/api-redhat_spec.rb +++ b/spec/api-redhat_spec.rb @@ -12,8 +12,13 @@ describe 'openstack-block-storage::api' do include_context 'block-storage-stubs' + it do + expect(chef_run).to_not create_file('/etc/apache2/conf-available/cinder-wsgi.conf') + end + it 'upgrades cinder api package' do expect(chef_run).to upgrade_package 'openstack-cinder' + expect(chef_run).to upgrade_package 'mod_wsgi' end it 'upgrades mysql python package' do diff --git a/spec/api_spec.rb b/spec/api_spec.rb index 6b76deb..406ddf1 100644 --- a/spec/api_spec.rb +++ b/spec/api_spec.rb @@ -12,34 +12,15 @@ describe 'openstack-block-storage::api' do include_context 'block-storage-stubs' include_examples 'common-logging' - include_examples 'creates_cinder_conf', 'execute[Clear cinder-api apache restart]', 'cinder', 'cinder', 'run' + include_examples 'creates_cinder_conf', 'service[apache2]', 'cinder', 'cinder', 'restart' it do - expect(chef_run).to nothing_execute('Clear cinder-api apache restart') - .with( - command: 'rm -f /var/chef/cache/cinder-api-apache-restarted' - ) - end - - %w( - /etc/cinder/cinder.conf - /etc/apache2/sites-available/cinder-api.conf - ).each do |f| - it "#{f} notifies execute[Clear cinder-api apache restart]" do - expect(chef_run.template(f)).to notify('execute[Clear cinder-api apache restart]').to(:run).immediately - end - end - - it do - expect(chef_run).to run_execute('cinder-api apache restart') - .with( - command: 'touch /var/chef/cache/cinder-api-apache-restarted', - creates: '/var/chef/cache/cinder-api-apache-restarted' - ) - end - - it do - expect(chef_run.execute('cinder-api apache restart')).to notify('service[apache2]').to(:restart).immediately + expect(chef_run).to create_file('/etc/apache2/conf-available/cinder-wsgi.conf').with( + owner: 'root', + group: 'www-data', + mode: '0640', + content: '# Chef openstack-block-storage: file to block config from package' + ) end it 'upgrades cinder api packages' do @@ -56,6 +37,116 @@ describe 'openstack-block-storage::api' do expect(chef_run).to run_execute('cinder-manage db sync').with(user: 'cinder', group: 'cinder') end + describe 'apache wsgi' do + let(:file) { '/etc/apache2/sites-available/cinder-api.conf' } + + it do + expect(chef_run).to create_template(file).with( + source: 'wsgi-template.conf.erb', + variables: { + daemon_process: 'cinder-wsgi', + group: 'cinder', + log_dir: '/var/log/apache2', + run_dir: '/var/lock/apache2', + server_entry: '/usr/bin/cinder-wsgi', + server_host: '127.0.0.1', + server_port: '8776', + user: 'cinder', + } + ) + end + it 'configures cinder-api.conf' do + [ + /VirtualHost 127.0.0.1:8776/, + /WSGIDaemonProcess cinder-wsgi processes=2 threads=10 user=cinder group=cinder display-name=%{GROUP}/, + /WSGIProcessGroup cinder-wsgi/, + %r{WSGIScriptAlias / /usr/bin/cinder-wsgi}, + %r{ErrorLog /var/log/apache2/cinder-wsgi_error.log}, + %r{CustomLog /var/log/apache2/cinder-wsgi_access.log combined}, + %r{WSGISocketPrefix /var/lock/apache2}, + ].each do |line| + expect(chef_run).to render_file(file).with_content(line) + end + expect(chef_run).to_not render_file(file).with_content(/SSLEngine On/) + end + it do + expect(chef_run.template(file)).to notify('service[apache2]').to(:restart) + end + + it do + expect(chef_run).to install_apache2_install('openstack').with(listen: '127.0.0.1:8776') + end + + it do + expect(chef_run).to enable_apache2_module('wsgi') + end + + it do + expect(chef_run).to_not enable_apache2_module('ssl') + end + + it do + expect(chef_run).to disable_apache2_conf('cinder-wsgi') + end + + it do + expect(chef_run).to enable_apache2_site('cinder-api') + end + + it do + expect(chef_run.apache2_site('cinder-api')).to notify('service[apache2]').to(:restart).immediately + end + context 'Enable SSL' do + cached(:chef_run) do + node.override['openstack']['block-storage']['ssl']['enabled'] = true + node.override['openstack']['block-storage']['ssl']['certfile'] = 'certfile' + node.override['openstack']['block-storage']['ssl']['keyfile'] = 'keyfile' + node.override['openstack']['block-storage']['ssl']['ca_certs_path'] = 'ca_certs_path' + node.override['openstack']['block-storage']['ssl']['protocol'] = 'protocol' + runner.converge(described_recipe) + end + it do + expect(chef_run).to enable_apache2_module('ssl') + end + it 'configures cinder-api.conf' do + [ + /SSLEngine On/, + /SSLCertificateFile certfile/, + /SSLCertificateKeyFile keyfile/, + /SSLCACertificatePath ca_certs_path/, + /SSLProtocol protocol/, + ].each do |line| + expect(chef_run).to render_file(file).with_content(line) + end + [ + /SSLCertificateChainFile/, + /SSLCipherSuite/, + /SSLVerifyClient/, + ].each do |line| + expect(chef_run).to_not render_file(file).with_content(line) + end + end + context 'Enable chainfile, ciphers & cert_required' do + cached(:chef_run) do + node.override['openstack']['block-storage']['ssl']['enabled'] = true + node.override['openstack']['block-storage']['ssl']['chainfile'] = 'chainfile' + node.override['openstack']['block-storage']['ssl']['ciphers'] = 'ciphers' + node.override['openstack']['block-storage']['ssl']['cert_required'] = true + runner.converge(described_recipe) + end + it 'configures cinder-api.conf' do + [ + /SSLCertificateChainFile chainfile/, + /SSLCipherSuite ciphers/, + /SSLVerifyClient require/, + ].each do |line| + expect(chef_run).to render_file(file).with_content(line) + end + end + end + end + end + describe 'policy file' do it 'does not manage policy file unless specified' do expect(chef_run).not_to create_remote_file('/etc/cinder/policy.json') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 549aa90..952eb0d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -56,6 +56,35 @@ shared_context 'block-storage-stubs' do stub_command('/usr/sbin/httpd -t').and_return(true) stub_command('/usr/sbin/apache2 -t').and_return(true) allow(Chef::Application).to receive(:fatal!) + # identity stubs + allow_any_instance_of(Chef::Recipe).to receive(:secret) + .with('secrets', 'credential_key0') + .and_return('thisiscredentialkey0') + allow_any_instance_of(Chef::Recipe).to receive(:secret) + .with('secrets', 'credential_key1') + .and_return('thisiscredentialkey1') + allow_any_instance_of(Chef::Recipe).to receive(:secret) + .with('secrets', 'fernet_key0') + .and_return('thisisfernetkey0') + allow_any_instance_of(Chef::Recipe).to receive(:secret) + .with('secrets', 'fernet_key1') + .and_return('thisisfernetkey1') + allow_any_instance_of(Chef::Recipe).to receive(:search_for) + .with('os-identity').and_return( + [{ + 'openstack' => { + 'identity' => { + 'admin_tenant_name' => 'admin', + 'admin_user' => 'admin', + }, + }, + }] + ) + allow_any_instance_of(Chef::Recipe).to receive(:memcached_servers) + .and_return([]) + allow_any_instance_of(Chef::Recipe).to receive(:rabbit_transport_url) + .with('identity') + .and_return('rabbit://openstack:mypass@127.0.0.1:5672') end end diff --git a/templates/default/wsgi-template.conf.erb b/templates/default/wsgi-template.conf.erb index ecf379b..2f5dfb6 100644 --- a/templates/default/wsgi-template.conf.erb +++ b/templates/default/wsgi-template.conf.erb @@ -1,11 +1,9 @@ <%= node["openstack"]["block-storage"]["custom_template_banner"] %> -Listen <%= @params[:server_host] %>:<%= @params[:server_port] %> - -:<%= @params[:server_port] %>> - WSGIDaemonProcess <%= @params[:daemon_process] %> processes=2 threads=10 user=<%= @params[:user] %> group=<%= @params[:group] %> display-name=%{GROUP} - WSGIProcessGroup <%= @params[:daemon_process] %> - WSGIScriptAlias / <%= @params[:server_entry] %> +:<%= @server_port %>> + WSGIDaemonProcess <%= @daemon_process %> processes=2 threads=10 user=<%= @user %> group=<%= @group %> display-name=%{GROUP} + WSGIProcessGroup <%= @daemon_process %> + WSGIScriptAlias / <%= @server_entry %> WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On @@ -14,29 +12,25 @@ Listen <%= @params[:server_host] %>:<%= @params[:server_port] %> ErrorLogFormat "%{cu}t %M" - ErrorLog <%= @params[:log_dir] %>/<%= @params[:daemon_process] %>_error.log - CustomLog <%= @params[:log_dir] %>/<%= @params[:daemon_process] %>_access.log combined -<% if [true, 'true', 'True'].include?(@params[:log_debug]) -%> - LogLevel debug -<% end -%> + ErrorLog <%= @log_dir %>/<%= @daemon_process %>_error.log + CustomLog <%= @log_dir %>/<%= @daemon_process %>_access.log combined +<% if node['openstack']['block-storage']['ssl']['enabled'] -%> -<% if @params[:use_ssl] -%> SSLEngine On - SSLCertificateFile <%= @params[:cert_file] %> - SSLCertificateKeyFile <%= @params[:key_file] %> - SSLCACertificatePath <%= @params[:ca_certs_path] %> -<% if @params[:chain_file] %> - SSLCertificateChainFile <%= @params[:chain_file] %> + SSLCertificateFile <%= node['openstack']['block-storage']['ssl']['certfile'] %> + SSLCertificateKeyFile <%= node['openstack']['block-storage']['ssl']['keyfile'] %> + SSLCACertificatePath <%= node['openstack']['block-storage']['ssl']['ca_certs_path'] %> +<% unless node['openstack']['block-storage']['ssl']['chainfile'].empty? %> + SSLCertificateChainFile <%= node['openstack']['block-storage']['ssl']['chainfile'] %> <% end -%> - SSLProtocol <%= @params[:protocol] %> -<% if @params[:ciphers] -%> - SSLCipherSuite <%= @params[:ciphers] %> + SSLProtocol <%= node['openstack']['block-storage']['ssl']['protocol'] %> +<% unless node['openstack']['block-storage']['ssl']['ciphers'].empty? -%> + SSLCipherSuite <%= node['openstack']['block-storage']['ssl']['ciphers'] %> <% end -%> -<% if @params[:cert_required] -%> +<% if node['openstack']['block-storage']['ssl']['cert_required'] -%> SSLVerifyClient require <% end -%> <% end -%> -WSGISocketPrefix <%= @params[:run_dir] -%> - +WSGISocketPrefix <%= @run_dir -%>