Split the dashboard and webserver recipes
In order to be able to use alternative webservers, split the parts relating to setting up the dashboard itself and setting up the webserver into two new recipes. Also introduce a new configuration variable, defaulting to `apache2`, which will be used in the `server` recipe to select the type of webserver being installed. Change-Id: I70dcb820239547b0059ad15d19d5e1689ddff3d3 blueprint: dashboard-split-horizon-apache
This commit is contained in:
parent
a142662fbd
commit
97404520bc
|
@ -20,6 +20,7 @@ This file is used to list changes made in each version of the openstack-dashboar
|
|||
* Set default to use only TLS for SSL. OpenStack security note OSSN-0039
|
||||
* Allow TraceEnable to be configured
|
||||
* Allow volume_api_version to be configured for Horizon
|
||||
* Allow webserver to be configurable
|
||||
|
||||
## 9.1
|
||||
* python_packages database client attributes have been moved to the -common cookbook
|
||||
|
|
20
README.md
20
README.md
|
@ -21,10 +21,23 @@ The following cookbooks are dependencies:
|
|||
Usage
|
||||
=====
|
||||
|
||||
horizon
|
||||
-------
|
||||
|
||||
Sets up the packages needed to run the Horizon dashboard and its dependencies.
|
||||
Will be included from the `server` recipe.
|
||||
|
||||
apache2-server
|
||||
--------------
|
||||
|
||||
Installs the Apache webserver and sets up an `mod_wsgi` container to run the
|
||||
Horizon dashboard. Will be included from the `server` recipe.
|
||||
|
||||
server
|
||||
------
|
||||
|
||||
Sets up the Horizon dashboard within an Apache `mod_wsgi` container.
|
||||
Sets up the Horizon dashboard and a webserver of type `['openstack']['dashboard']['server_type']`
|
||||
to run it, default type is 'apache2'.
|
||||
|
||||
```json
|
||||
"run_list": [
|
||||
|
@ -35,8 +48,9 @@ Sets up the Horizon dashboard within an Apache `mod_wsgi` container.
|
|||
Attributes
|
||||
==========
|
||||
|
||||
* `openstack['dashboard']['server_type']` - Selects the type of webserver to install
|
||||
* `openstack['dashboard']['db']['username']` - Username for horizon database access
|
||||
* `openstack['dashboard']['server_hostname']` - Sets the ServerName in the Apache config
|
||||
* `openstack['dashboard']['server_hostname']` - Sets the ServerName in the webserver config
|
||||
* `openstack['dashboard']['allowed_hosts']` - List of host/domain names we can service (default: '\[\*\]')
|
||||
* `openstack['dashboard']['dash_path']` - Base path for dashboard files (document root)
|
||||
* `openstack['dashboard']['wsgi_path']` - Path for wsgi dir
|
||||
|
@ -115,12 +129,14 @@ License and Author
|
|||
| **Author** | Jian Hua Geng (<gengjh@cn.ibm.com>) |
|
||||
| **Author** | Ionut Artarisi (<iartarisi@suse.cz>) |
|
||||
| **Author** | Eric Zhou (<iartarisi@suse.cz>) |
|
||||
| **Author** | Jens Rosenboom (<j.rosenboom@x-ion.de>) |
|
||||
| | |
|
||||
| **Copyright** | Copyright (c) 2012, Rackspace US, Inc. |
|
||||
| **Copyright** | Copyright (c) 2012-2013, AT&T Services, Inc. |
|
||||
| **Copyright** | Copyright (c) 2013, Opscode, Inc. |
|
||||
| **Copyright** | Copyright (c) 2013-2014, IBM, Corp. |
|
||||
| **Copyright** | Copyright (c) 2013-2014, SUSE Linux GmbH. |
|
||||
| **Copyright** | Copyright (c) 2014, x-ion GmbH. |
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -26,6 +26,8 @@ default['openstack']['dashboard']['custom_template_banner'] = '
|
|||
# Do not edit, changes will be overwritten
|
||||
'
|
||||
|
||||
default['openstack']['dashboard']['server_type'] = 'apache2'
|
||||
|
||||
default['openstack']['dashboard']['debug'] = false
|
||||
|
||||
# The Keystone role used by default for users logging into the dashboard
|
||||
|
|
|
@ -2,11 +2,13 @@ name 'openstack-dashboard'
|
|||
maintainer 'openstack-chef'
|
||||
maintainer_email 'opscode-chef-openstack@googlegroups.com'
|
||||
license 'Apache 2.0'
|
||||
description 'Installs/Configures the OpenStack Dasboard (Horizon)'
|
||||
description 'Installs/Configures the OpenStack Dashboard (Horizon)'
|
||||
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
||||
version '10.0'
|
||||
|
||||
recipe 'openstack-dashboard::server', 'Sets up the Horizon dashboard within an Apache `mod_wsgi` container.'
|
||||
recipe 'openstack-dashboard::horizon', 'Sets up the Horizon dashboard.'
|
||||
recipe 'openstack-dashboard::apache2-server', 'Sets up an Apache `mod_wsgi` container to run the dashboard.'
|
||||
recipe 'openstack-dashboard::server', 'Sets up the Horizon dashboard and webserver to run it.'
|
||||
|
||||
%w{ ubuntu fedora redhat centos suse }.each do |os|
|
||||
supports os
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
# encoding: UTF-8
|
||||
#
|
||||
# Cookbook Name:: openstack-dashboard
|
||||
# Recipe:: apache2-server
|
||||
#
|
||||
# Copyright 2012, Rackspace US, Inc.
|
||||
# Copyright 2012-2013, AT&T Services, Inc.
|
||||
# Copyright 2013-2014, IBM, Corp.
|
||||
# Copyright 2014, SUSE Linux, GmbH.
|
||||
# Copyright 2014, x-ion GmbH.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
require 'uri'
|
||||
|
||||
class ::Chef::Recipe # rubocop:disable Documentation
|
||||
include ::Openstack
|
||||
end
|
||||
|
||||
#
|
||||
# Workaround to install apache2 on a fedora machine with selinux set to enforcing
|
||||
# TODO(breu): this should move to a subscription of the template from the apache2 recipe
|
||||
# and it should simply be a restorecon on the configuration file(s) and not
|
||||
# change the selinux mode
|
||||
#
|
||||
execute 'set-selinux-permissive' do
|
||||
command '/sbin/setenforce Permissive'
|
||||
action :run
|
||||
|
||||
only_if "[ ! -e /etc/httpd/conf/httpd.conf ] && [ -e /etc/redhat-release ] && [ $(/sbin/sestatus | grep -c '^Current mode:.*enforcing') -eq 1 ]"
|
||||
end
|
||||
|
||||
include_recipe 'apache2'
|
||||
include_recipe 'apache2::mod_wsgi'
|
||||
include_recipe 'apache2::mod_rewrite'
|
||||
include_recipe 'apache2::mod_ssl'
|
||||
|
||||
#
|
||||
# Workaround to re-enable selinux after installing apache on a fedora machine that has
|
||||
# selinux enabled and is currently permissive and the configuration set to enforcing.
|
||||
# TODO(breu): get the other one working and this won't be necessary
|
||||
#
|
||||
execute 'set-selinux-enforcing' do
|
||||
command '/sbin/setenforce Enforcing ; restorecon -R /etc/httpd'
|
||||
action :run
|
||||
|
||||
only_if "[ -e /etc/httpd/conf/httpd.conf ] && [ -e /etc/redhat-release ] && [ $(/sbin/sestatus | grep -c '^Current mode:.*permissive') -eq 1 ] && [ $(/sbin/sestatus | grep -c '^Mode from config file:.*enforcing') -eq 1 ]"
|
||||
end
|
||||
|
||||
# delete the openstack-dashboard.conf before reload apache2 service on redhat and centos
|
||||
# since this file is not valid on those platforms for the apache2 service.
|
||||
file "#{node["apache"]["dir"]}/conf.d/openstack-dashboard.conf" do
|
||||
action :delete
|
||||
backup false
|
||||
|
||||
only_if { platform_family?('rhel') } # :pragma-foodcritic: ~FC024 - won't fix this
|
||||
end
|
||||
|
||||
cert_file = "#{node['openstack']['dashboard']['ssl']['dir']}/certs/#{node['openstack']['dashboard']['ssl']['cert']}"
|
||||
cert_mode = 00644
|
||||
cert_owner = 'root'
|
||||
cert_group = 'root'
|
||||
if node['openstack']['dashboard']['ssl']['cert_url']
|
||||
remote_file cert_file do
|
||||
sensitive true
|
||||
source node['openstack']['dashboard']['ssl']['cert_url']
|
||||
mode cert_mode
|
||||
owner cert_owner
|
||||
group cert_group
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
else
|
||||
cookbook_file cert_file do
|
||||
sensitive true
|
||||
source 'horizon.pem'
|
||||
mode cert_mode
|
||||
owner cert_owner
|
||||
group cert_group
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
end
|
||||
|
||||
key_file = "#{node['openstack']['dashboard']['ssl']['dir']}/private/#{node['openstack']['dashboard']['ssl']['key']}"
|
||||
key_mode = 00640
|
||||
key_owner = 'root'
|
||||
case node['platform_family']
|
||||
when 'debian'
|
||||
key_group = 'ssl-cert'
|
||||
else
|
||||
key_group = 'root'
|
||||
end
|
||||
|
||||
if node['openstack']['dashboard']['ssl']['key_url']
|
||||
remote_file key_file do
|
||||
sensitive true
|
||||
source node['openstack']['dashboard']['ssl']['key_url']
|
||||
mode key_mode
|
||||
owner key_owner
|
||||
group key_group
|
||||
|
||||
notifies :restart, 'service[apache2]', :immediately
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
else
|
||||
cookbook_file key_file do
|
||||
sensitive true
|
||||
source 'horizon.key'
|
||||
mode key_mode
|
||||
owner key_owner
|
||||
group key_group
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
end
|
||||
|
||||
# make sure this file has correct permission
|
||||
file node['openstack']['dashboard']['secret_key_path'] do
|
||||
owner node['openstack']['dashboard']['horizon_user']
|
||||
group node['openstack']['dashboard']['horizon_group']
|
||||
mode 00600
|
||||
# the only time the file should be created is if we have secret_key_content
|
||||
# set, otherwise let apache create it when someone first accesses the
|
||||
# dashboard
|
||||
if node['openstack']['dashboard']['secret_key_content'].nil?
|
||||
only_if { ::File.exists?(node['openstack']['dashboard']['secret_key_path']) }
|
||||
else
|
||||
content node['openstack']['dashboard']['secret_key_content']
|
||||
notifies :restart, 'service[apache2]'
|
||||
end
|
||||
end
|
||||
|
||||
# stop apache bitching
|
||||
directory "#{node["openstack"]["dashboard"]["dash_path"]}/.blackhole" do
|
||||
owner 'root'
|
||||
action :create
|
||||
end
|
||||
|
||||
template node['openstack']['dashboard']['apache']['sites-path'] do
|
||||
source 'dash-site.erb'
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode 00644
|
||||
|
||||
variables(
|
||||
ssl_cert_file: "#{node["openstack"]["dashboard"]["ssl"]["dir"]}/certs/#{node["openstack"]["dashboard"]["ssl"]["cert"]}",
|
||||
ssl_key_file: "#{node["openstack"]["dashboard"]["ssl"]["dir"]}/private/#{node["openstack"]["dashboard"]["ssl"]["key"]}"
|
||||
)
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
notifies :reload, 'service[apache2]', :immediately
|
||||
end
|
||||
|
||||
# The `apache_site` provided by the apache2 cookbook
|
||||
# is not an LWRP. Guards do not apply to definitions.
|
||||
# http://tickets.opscode.com/browse/CHEF-778
|
||||
if platform_family?('debian')
|
||||
apache_site '000-default' do
|
||||
enable false
|
||||
end
|
||||
elsif platform_family?('rhel') then
|
||||
apache_site 'default' do
|
||||
enable false
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
end
|
||||
|
||||
apache_site 'openstack-dashboard' do
|
||||
enable true
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
notifies :reload, 'service[apache2]', :immediately
|
||||
end
|
||||
|
||||
execute 'restore-selinux-context' do
|
||||
command 'restorecon -Rv /etc/httpd /etc/pki; chcon -R -t httpd_sys_content_t /usr/share/openstack-dashboard || :'
|
||||
action :nothing
|
||||
|
||||
only_if { platform_family?('fedora') }
|
||||
end
|
|
@ -0,0 +1,106 @@
|
|||
# encoding: UTF-8
|
||||
#
|
||||
# Cookbook Name:: openstack-dashboard
|
||||
# Recipe:: horizon
|
||||
#
|
||||
# Copyright 2012, Rackspace US, Inc.
|
||||
# Copyright 2012-2013, AT&T Services, Inc.
|
||||
# Copyright 2013-2014, IBM, Corp.
|
||||
# Copyright 2014, SUSE Linux, GmbH.
|
||||
# Copyright 2014, x-ion, GmbH.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
require 'uri'
|
||||
|
||||
class ::Chef::Recipe # rubocop:disable Documentation
|
||||
include ::Openstack
|
||||
end
|
||||
|
||||
platform_options = node['openstack']['dashboard']['platform']
|
||||
|
||||
identity_admin_endpoint = endpoint 'identity-admin'
|
||||
auth_admin_uri = auth_uri_transform identity_admin_endpoint.to_s, node['openstack']['dashboard']['api']['auth']['version']
|
||||
identity_endpoint = endpoint 'identity-api'
|
||||
auth_uri = auth_uri_transform identity_endpoint.to_s, node['openstack']['dashboard']['api']['auth']['version']
|
||||
|
||||
db_pass = get_password 'db', 'horizon'
|
||||
db_info = db 'dashboard'
|
||||
|
||||
python_packages = node['openstack']['db']['python_packages'][db_info['service_type']]
|
||||
# Add dashboard specific database packages
|
||||
python_packages += Array(node['openstack']['dashboard']['db_python_packages'][db_info['service_type']])
|
||||
(platform_options['horizon_packages'] + python_packages).each do |pkg|
|
||||
package pkg do
|
||||
action :upgrade
|
||||
options platform_options['package_overrides']
|
||||
end
|
||||
end
|
||||
|
||||
if node['openstack']['dashboard']['session_backend'] == 'memcached'
|
||||
platform_options['memcache_python_packages'].each do |pkg|
|
||||
package pkg
|
||||
end
|
||||
end
|
||||
|
||||
memcached = memcached_servers
|
||||
|
||||
template node['openstack']['dashboard']['local_settings_path'] do
|
||||
source 'local_settings.py.erb'
|
||||
owner 'root'
|
||||
group node['openstack']['dashboard']['horizon_group']
|
||||
mode 00640
|
||||
sensitive true
|
||||
|
||||
variables(
|
||||
db_pass: db_pass,
|
||||
db_info: db_info,
|
||||
auth_uri: auth_uri,
|
||||
auth_admin_uri: auth_admin_uri,
|
||||
memcached_servers: memcached
|
||||
)
|
||||
|
||||
notifies :restart, "service[#{node['openstack']['dashboard']['server_type']}]", :immediately
|
||||
end
|
||||
|
||||
execute 'openstack-dashboard syncdb' do
|
||||
cwd node['openstack']['dashboard']['django_path']
|
||||
environment 'PYTHONPATH' => "/etc/openstack-dashboard:#{node['openstack']['dashboard']['django_path']}:$PYTHONPATH"
|
||||
command 'python manage.py syncdb --noinput'
|
||||
action :run
|
||||
only_if do
|
||||
node['openstack']['dashboard']['session_backend'] == 'sql' &&
|
||||
node['openstack']['db']['dashboard']['migrate'] ||
|
||||
db_info['service_type'] == 'sqlite'
|
||||
end
|
||||
end
|
||||
|
||||
directory "#{node['openstack']['dashboard']['dash_path']}/local" do
|
||||
owner 'root'
|
||||
group node['openstack']['dashboard']['horizon_group']
|
||||
mode 02770
|
||||
action :create
|
||||
end
|
||||
|
||||
# ubuntu includes their own branding - we need to delete this until ubuntu makes this a
|
||||
# configurable paramter
|
||||
package 'openstack-dashboard-ubuntu-theme' do
|
||||
action :purge
|
||||
|
||||
only_if { platform_family?('debian') }
|
||||
end
|
||||
|
||||
# TODO(shep)
|
||||
# Horizon has a forced dependency on there being a volume service endpoint in your keystone catalog
|
||||
# https://answers.launchpad.net/horizon/+question/189551
|
|
@ -7,6 +7,7 @@
|
|||
# Copyright 2012-2013, AT&T Services, Inc.
|
||||
# Copyright 2013-2014, IBM, Corp.
|
||||
# Copyright 2014, SUSE Linux, GmbH.
|
||||
# Copyright 2014, x-ion GmbH.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -21,249 +22,5 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
|
||||
require 'uri'
|
||||
|
||||
class ::Chef::Recipe # rubocop:disable Documentation
|
||||
include ::Openstack
|
||||
end
|
||||
|
||||
#
|
||||
# Workaround to install apache2 on a fedora machine with selinux set to enforcing
|
||||
# TODO(breu): this should move to a subscription of the template from the apache2 recipe
|
||||
# and it should simply be a restorecon on the configuration file(s) and not
|
||||
# change the selinux mode
|
||||
#
|
||||
execute 'set-selinux-permissive' do
|
||||
command '/sbin/setenforce Permissive'
|
||||
action :run
|
||||
|
||||
only_if "[ ! -e /etc/httpd/conf/httpd.conf ] && [ -e /etc/redhat-release ] && [ $(/sbin/sestatus | grep -c '^Current mode:.*enforcing') -eq 1 ]"
|
||||
end
|
||||
|
||||
platform_options = node['openstack']['dashboard']['platform']
|
||||
|
||||
include_recipe 'apache2'
|
||||
include_recipe 'apache2::mod_wsgi'
|
||||
include_recipe 'apache2::mod_rewrite'
|
||||
include_recipe 'apache2::mod_ssl'
|
||||
|
||||
#
|
||||
# Workaround to re-enable selinux after installing apache on a fedora machine that has
|
||||
# selinux enabled and is currently permissive and the configuration set to enforcing.
|
||||
# TODO(breu): get the other one working and this won't be necessary
|
||||
#
|
||||
execute 'set-selinux-enforcing' do
|
||||
command '/sbin/setenforce Enforcing ; restorecon -R /etc/httpd'
|
||||
action :run
|
||||
|
||||
only_if "[ -e /etc/httpd/conf/httpd.conf ] && [ -e /etc/redhat-release ] && [ $(/sbin/sestatus | grep -c '^Current mode:.*permissive') -eq 1 ] && [ $(/sbin/sestatus | grep -c '^Mode from config file:.*enforcing') -eq 1 ]"
|
||||
end
|
||||
|
||||
identity_admin_endpoint = endpoint 'identity-admin'
|
||||
auth_admin_uri = auth_uri_transform identity_admin_endpoint.to_s, node['openstack']['dashboard']['api']['auth']['version']
|
||||
identity_endpoint = endpoint 'identity-api'
|
||||
auth_uri = auth_uri_transform identity_endpoint.to_s, node['openstack']['dashboard']['api']['auth']['version']
|
||||
|
||||
db_pass = get_password 'db', 'horizon'
|
||||
db_info = db 'dashboard'
|
||||
|
||||
python_packages = node['openstack']['db']['python_packages'][db_info['service_type']]
|
||||
# Add dashboard specific database packages
|
||||
python_packages += Array(node['openstack']['dashboard']['db_python_packages'][db_info['service_type']])
|
||||
(platform_options['horizon_packages'] + python_packages).each do |pkg|
|
||||
package pkg do
|
||||
action :upgrade
|
||||
options platform_options['package_overrides']
|
||||
end
|
||||
end
|
||||
|
||||
if node['openstack']['dashboard']['session_backend'] == 'memcached'
|
||||
platform_options['memcache_python_packages'].each do |pkg|
|
||||
package pkg
|
||||
end
|
||||
end
|
||||
|
||||
memcached = memcached_servers
|
||||
|
||||
# delete the openstack-dashboard.conf before reload apache2 service on redhat and centos
|
||||
# since this file is not valid on those platforms for the apache2 service.
|
||||
file "#{node["apache"]["dir"]}/conf.d/openstack-dashboard.conf" do
|
||||
action :delete
|
||||
backup false
|
||||
|
||||
only_if { platform_family?('rhel') } # :pragma-foodcritic: ~FC024 - won't fix this
|
||||
end
|
||||
|
||||
template node['openstack']['dashboard']['local_settings_path'] do
|
||||
source 'local_settings.py.erb'
|
||||
owner 'root'
|
||||
group node['openstack']['dashboard']['horizon_group']
|
||||
mode 00640
|
||||
sensitive true
|
||||
|
||||
variables(
|
||||
db_pass: db_pass,
|
||||
db_info: db_info,
|
||||
auth_uri: auth_uri,
|
||||
auth_admin_uri: auth_admin_uri,
|
||||
memcached_servers: memcached
|
||||
)
|
||||
|
||||
notifies :restart, 'service[apache2]', :immediately
|
||||
end
|
||||
|
||||
execute 'openstack-dashboard syncdb' do
|
||||
cwd node['openstack']['dashboard']['django_path']
|
||||
environment 'PYTHONPATH' => "/etc/openstack-dashboard:#{node['openstack']['dashboard']['django_path']}:$PYTHONPATH"
|
||||
command 'python manage.py syncdb --noinput'
|
||||
action :run
|
||||
only_if do
|
||||
node['openstack']['dashboard']['session_backend'] == 'sql' &&
|
||||
node['openstack']['db']['dashboard']['migrate'] ||
|
||||
db_info['service_type'] == 'sqlite'
|
||||
end
|
||||
end
|
||||
|
||||
cert_file = "#{node['openstack']['dashboard']['ssl']['dir']}/certs/#{node['openstack']['dashboard']['ssl']['cert']}"
|
||||
cert_mode = 00644
|
||||
cert_owner = 'root'
|
||||
cert_group = 'root'
|
||||
if node['openstack']['dashboard']['ssl']['cert_url']
|
||||
remote_file cert_file do
|
||||
sensitive true
|
||||
source node['openstack']['dashboard']['ssl']['cert_url']
|
||||
mode cert_mode
|
||||
owner cert_owner
|
||||
group cert_group
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
else
|
||||
cookbook_file cert_file do
|
||||
sensitive true
|
||||
source 'horizon.pem'
|
||||
mode cert_mode
|
||||
owner cert_owner
|
||||
group cert_group
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
end
|
||||
|
||||
key_file = "#{node['openstack']['dashboard']['ssl']['dir']}/private/#{node['openstack']['dashboard']['ssl']['key']}"
|
||||
key_mode = 00640
|
||||
key_owner = 'root'
|
||||
case node['platform_family']
|
||||
when 'debian'
|
||||
key_group = 'ssl-cert'
|
||||
else
|
||||
key_group = 'root'
|
||||
end
|
||||
|
||||
if node['openstack']['dashboard']['ssl']['key_url']
|
||||
remote_file key_file do
|
||||
sensitive true
|
||||
source node['openstack']['dashboard']['ssl']['key_url']
|
||||
mode key_mode
|
||||
owner key_owner
|
||||
group key_group
|
||||
|
||||
notifies :restart, 'service[apache2]', :immediately
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
else
|
||||
cookbook_file key_file do
|
||||
sensitive true
|
||||
source 'horizon.key'
|
||||
mode key_mode
|
||||
owner key_owner
|
||||
group key_group
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
end
|
||||
|
||||
directory "#{node['openstack']['dashboard']['dash_path']}/local" do
|
||||
owner 'root'
|
||||
group node['openstack']['dashboard']['horizon_group']
|
||||
mode 02770
|
||||
action :create
|
||||
end
|
||||
|
||||
# make sure this file has correct permission
|
||||
file node['openstack']['dashboard']['secret_key_path'] do
|
||||
owner node['openstack']['dashboard']['horizon_user']
|
||||
group node['openstack']['dashboard']['horizon_group']
|
||||
mode 00600
|
||||
# the only time the file should be created is if we have secret_key_content
|
||||
# set, otherwise let apache create it when someone first accesses the
|
||||
# dashboard
|
||||
if node['openstack']['dashboard']['secret_key_content'].nil?
|
||||
only_if { ::File.exists?(node['openstack']['dashboard']['secret_key_path']) }
|
||||
else
|
||||
content node['openstack']['dashboard']['secret_key_content']
|
||||
notifies :restart, 'service[apache2]'
|
||||
end
|
||||
end
|
||||
|
||||
# stop apache bitching
|
||||
directory "#{node["openstack"]["dashboard"]["dash_path"]}/.blackhole" do
|
||||
owner 'root'
|
||||
action :create
|
||||
end
|
||||
|
||||
template node['openstack']['dashboard']['apache']['sites-path'] do
|
||||
source 'dash-site.erb'
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode 00644
|
||||
|
||||
variables(
|
||||
ssl_cert_file: "#{node["openstack"]["dashboard"]["ssl"]["dir"]}/certs/#{node["openstack"]["dashboard"]["ssl"]["cert"]}",
|
||||
ssl_key_file: "#{node["openstack"]["dashboard"]["ssl"]["dir"]}/private/#{node["openstack"]["dashboard"]["ssl"]["key"]}"
|
||||
)
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
notifies :reload, 'service[apache2]', :immediately
|
||||
end
|
||||
|
||||
# ubuntu includes their own branding - we need to delete this until ubuntu makes this a
|
||||
# configurable paramter
|
||||
package 'openstack-dashboard-ubuntu-theme' do
|
||||
action :purge
|
||||
|
||||
only_if { platform_family?('debian') }
|
||||
end
|
||||
|
||||
# The `apache_site` provided by the apache2 cookbook
|
||||
# is not an LWRP. Guards do not apply to definitions.
|
||||
# http://tickets.opscode.com/browse/CHEF-778
|
||||
if platform_family?('debian')
|
||||
apache_site '000-default' do
|
||||
enable false
|
||||
end
|
||||
elsif platform_family?('rhel') then
|
||||
apache_site 'default' do
|
||||
enable false
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
end
|
||||
end
|
||||
|
||||
apache_site 'openstack-dashboard' do
|
||||
enable true
|
||||
|
||||
notifies :run, 'execute[restore-selinux-context]', :immediately
|
||||
notifies :reload, 'service[apache2]', :immediately
|
||||
end
|
||||
|
||||
execute 'restore-selinux-context' do
|
||||
command 'restorecon -Rv /etc/httpd /etc/pki; chcon -R -t httpd_sys_content_t /usr/share/openstack-dashboard || :'
|
||||
action :nothing
|
||||
|
||||
only_if { platform_family?('fedora') }
|
||||
end
|
||||
|
||||
# TODO(shep)
|
||||
# Horizon has a forced dependency on there being a volume service endpoint in your keystone catalog
|
||||
# https://answers.launchpad.net/horizon/+question/189551
|
||||
include_recipe 'openstack-dashboard::horizon'
|
||||
include_recipe "openstack-dashboard::#{node['openstack']['dashboard']['server_type']}-server"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# encoding: UTF-8
|
||||
require_relative 'spec_helper'
|
||||
|
||||
describe 'openstack-dashboard::server' do
|
||||
describe 'openstack-dashboard::apache2-server' do
|
||||
|
||||
describe 'redhat' do
|
||||
|
||||
|
@ -20,47 +20,12 @@ describe 'openstack-dashboard::server' do
|
|||
expect(chef_run).to run_execute(cmd)
|
||||
end
|
||||
|
||||
it 'installs packages' do
|
||||
expect(chef_run).to upgrade_package('openstack-dashboard')
|
||||
expect(chef_run).to upgrade_package('MySQL-python')
|
||||
end
|
||||
|
||||
it 'installs db2 python packages if explicitly told' do
|
||||
node.set['openstack']['db']['dashboard']['service_type'] = 'db2'
|
||||
%w{python-ibm-db python-ibm-db-django python-ibm-db-sa}.each do |pkg|
|
||||
expect(chef_run).to upgrade_package(pkg)
|
||||
end
|
||||
end
|
||||
|
||||
it 'executes set-selinux-enforcing' do
|
||||
cmd = '/sbin/setenforce Enforcing ; restorecon -R /etc/httpd'
|
||||
|
||||
expect(chef_run).to run_execute(cmd)
|
||||
end
|
||||
|
||||
describe 'local_settings' do
|
||||
let(:file) { chef_run.template('/etc/openstack-dashboard/local_settings') }
|
||||
|
||||
it 'has proper owner' do
|
||||
expect(file.owner).to eq('root')
|
||||
expect(file.group).to eq('apache')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', file.mode)).to eq('640')
|
||||
end
|
||||
|
||||
it 'has urls set' do
|
||||
[
|
||||
%r(^LOGIN_URL = '/auth/login/'$),
|
||||
%r(^LOGOUT_URL = '/auth/logout/'$),
|
||||
/^LOGIN_REDIRECT_URL = '\/'$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'certs' do
|
||||
let(:crt) { chef_run.cookbook_file('/etc/pki/tls/certs/horizon.pem') }
|
||||
let(:key) { chef_run.cookbook_file('/etc/pki/tls/private/horizon.key') }
|
||||
|
@ -89,11 +54,6 @@ describe 'openstack-dashboard::server' do
|
|||
expect(chef_run).to delete_file(file)
|
||||
end
|
||||
|
||||
it 'does not remove openstack-dashboard-ubuntu-theme package' do
|
||||
|
||||
expect(chef_run).not_to purge_package('openstack-dashboard-ubuntu-theme')
|
||||
end
|
||||
|
||||
it 'does not execute restore-selinux-context' do
|
||||
cmd = 'restorecon -Rv /etc/httpd /etc/pki; chcon -R -t httpd_sys_content_t /usr/share/openstack-dashboard || :'
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# encoding: UTF-8
|
||||
require_relative 'spec_helper'
|
||||
|
||||
describe 'openstack-dashboard::apache2-server' do
|
||||
|
||||
describe 'suse' do
|
||||
|
||||
let(:runner) { ChefSpec::Runner.new(SUSE_OPTS) }
|
||||
let(:node) { runner.node }
|
||||
let(:chef_run) do
|
||||
runner.converge(described_recipe)
|
||||
end
|
||||
|
||||
include_context 'non_redhat_stubs'
|
||||
include_context 'dashboard_stubs'
|
||||
|
||||
it 'creates .blackhole dir with proper owner' do
|
||||
dir = '/srv/www/openstack-dashboard/openstack_dashboard/.blackhole'
|
||||
expect(chef_run.directory(dir).owner).to eq('root')
|
||||
end
|
||||
|
||||
it 'has correct ownership on file with attribute defaults' do
|
||||
file = chef_run.file('/srv/www/openstack-dashboard/openstack_dashboard/local/.secret_key_store')
|
||||
expect(file.owner).to eq('wwwrun')
|
||||
expect(file.group).to eq('www')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,404 @@
|
|||
# encoding: UTF-8
|
||||
require_relative 'spec_helper'
|
||||
|
||||
shared_examples 'virtualhost port configurator' do |port_attribute_name, port_attribute_value|
|
||||
let(:virtualhost_directive) { "<VirtualHost \\*:#{port_attribute_value}>" }
|
||||
before do
|
||||
node.set['openstack']['dashboard'][port_attribute_name] = port_attribute_value
|
||||
end
|
||||
|
||||
it "sets Listen and NameVirtualHost directives when apache's listen_ports does not include #{port_attribute_value}" do
|
||||
node.set['apache']['listen_ports'] = [port_attribute_value.to_i + 1]
|
||||
%w(Listen NameVirtualHost).each do |directive|
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{directive} \*:#{port_attribute_value}$/)
|
||||
end
|
||||
end
|
||||
|
||||
it "does not set Listen and NameVirtualHost directives when apache's listen_ports include #{port_attribute_value}" do
|
||||
node.set['apache']['listen_ports'] = [port_attribute_value]
|
||||
chef_run.converge(described_recipe)
|
||||
%w(Listen NameVirtualHost).each do |directive|
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^#{directive} \*:#{port_attribute_value}$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the VirtualHost directive' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{virtualhost_directive}$/)
|
||||
end
|
||||
|
||||
context 'server_hostname' do
|
||||
it 'sets the value if the server_hostname is present' do
|
||||
node.set['openstack']['dashboard']['server_hostname'] = 'server_hostname_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{virtualhost_directive}\s*ServerName server_hostname_value$/)
|
||||
end
|
||||
|
||||
it 'does not set the value if the server_hostname is not present' do
|
||||
node.set['openstack']['dashboard']['server_hostname'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^#{virtualhost_directive}\s*ServerName$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'openstack-dashboard::apache2-server' do
|
||||
|
||||
describe 'ubuntu' do
|
||||
|
||||
let(:runner) { ChefSpec::Runner.new(UBUNTU_OPTS) }
|
||||
let(:node) { runner.node }
|
||||
let(:chef_run) do
|
||||
runner.converge(described_recipe)
|
||||
end
|
||||
|
||||
let(:chef_run_session_sql) do
|
||||
node.set['openstack']['dashboard']['session_backend'] = 'sql'
|
||||
runner.converge(described_recipe)
|
||||
end
|
||||
|
||||
include_context 'non_redhat_stubs'
|
||||
include_context 'dashboard_stubs'
|
||||
|
||||
it 'does not execute set-selinux-permissive' do
|
||||
cmd = '/sbin/setenforce Permissive'
|
||||
expect(chef_run).not_to run_execute(cmd)
|
||||
end
|
||||
|
||||
it 'installs apache packages' do
|
||||
expect(chef_run).to include_recipe('apache2')
|
||||
expect(chef_run).to include_recipe('apache2::mod_wsgi')
|
||||
expect(chef_run).to include_recipe('apache2::mod_rewrite')
|
||||
expect(chef_run).to include_recipe('apache2::mod_ssl')
|
||||
end
|
||||
|
||||
it 'does not execute set-selinux-enforcing' do
|
||||
cmd = '/sbin/setenforce Enforcing ; restorecon -R /etc/httpd'
|
||||
expect(chef_run).not_to run_execute(cmd)
|
||||
end
|
||||
|
||||
describe 'certs' do
|
||||
let(:crt) { chef_run.cookbook_file('/etc/ssl/certs/horizon.pem') }
|
||||
let(:key) { chef_run.cookbook_file('/etc/ssl/private/horizon.key') }
|
||||
let(:remote_key) { chef_run.remote_file('/etc/ssl/private/horizon.key') }
|
||||
|
||||
it 'has proper owner and group' do
|
||||
expect(crt.owner).to eq('root')
|
||||
expect(crt.group).to eq('root')
|
||||
expect(key.owner).to eq('root')
|
||||
expect(key.group).to eq('ssl-cert')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', crt.mode)).to eq('644')
|
||||
expect(sprintf('%o', key.mode)).to eq('640')
|
||||
end
|
||||
|
||||
it 'has proper sensitvity' do
|
||||
expect(crt.sensitive).to eq(true)
|
||||
expect(key.sensitive).to eq(true)
|
||||
end
|
||||
|
||||
it 'notifies restore-selinux-context' do
|
||||
expect(crt).to notify('execute[restore-selinux-context]').to(:run)
|
||||
expect(key).to notify('execute[restore-selinux-context]').to(:run)
|
||||
end
|
||||
|
||||
it 'does not download certs if not needed' do
|
||||
expect(chef_run).not_to create_remote_file('/etc/ssl/certs/horizon.pem')
|
||||
expect(chef_run).not_to create_remote_file('/etc/ssl/private/horizon.key')
|
||||
end
|
||||
|
||||
it 'downloads certs if needed and restarts apache' do
|
||||
node.set['openstack']['dashboard']['ssl']['cert_url'] = 'http://server/mycert.pem'
|
||||
node.set['openstack']['dashboard']['ssl']['key_url'] = 'http://server/mykey.key'
|
||||
expect(chef_run).to create_remote_file('/etc/ssl/certs/horizon.pem').with(
|
||||
sensitive: true,
|
||||
user: 'root',
|
||||
group: 'root',
|
||||
mode: 0644
|
||||
)
|
||||
expect(chef_run).to create_remote_file('/etc/ssl/private/horizon.key').with(
|
||||
sensitive: true,
|
||||
user: 'root',
|
||||
group: 'ssl-cert',
|
||||
mode: 0640
|
||||
)
|
||||
expect(remote_key).to notify('service[apache2]').to(:restart)
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates .blackhole dir with proper owner' do
|
||||
dir = '/usr/share/openstack-dashboard/openstack_dashboard/.blackhole'
|
||||
|
||||
expect(chef_run.directory(dir).owner).to eq('root')
|
||||
end
|
||||
|
||||
describe 'openstack-dashboard virtual host' do
|
||||
let(:file) { chef_run.template('/etc/apache2/sites-available/openstack-dashboard') }
|
||||
|
||||
it 'has proper owner' do
|
||||
expect(file.owner).to eq('root')
|
||||
expect(file.group).to eq('root')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', file.mode)).to eq('644')
|
||||
end
|
||||
|
||||
context 'template content' do
|
||||
let(:rewrite_ssl_directive) { /^\s*RewriteEngine On\s*RewriteCond \%\{HTTPS\} off$/ }
|
||||
let(:default_rewrite_rule) { %r(^\s*RewriteRule \^\(\.\*\)\$ https\://%\{HTTP_HOST\}%\{REQUEST_URI\} \[L,R\]$) }
|
||||
|
||||
it 'has the default banner' do
|
||||
node.set['openstack']['dashboard']['custom_template_banner'] = 'custom_template_banner_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^custom_template_banner_value$/)
|
||||
end
|
||||
|
||||
it_should_behave_like 'virtualhost port configurator', 'http_port', 8080
|
||||
|
||||
context 'with use_ssl enabled' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = true
|
||||
end
|
||||
|
||||
it_should_behave_like 'virtualhost port configurator', 'https_port', 4433
|
||||
|
||||
it 'shows rewrite ssl directive' do
|
||||
expect(chef_run).to render_file(file.name).with_content(rewrite_ssl_directive)
|
||||
end
|
||||
|
||||
context 'rewrite rule' do
|
||||
it 'shows the default rewrite rule when http_port is 80 and https_port is 443' do
|
||||
node.set['openstack']['dashboard']['http_port'] = 80
|
||||
node.set['openstack']['dashboard']['https_port'] = 443
|
||||
expect(chef_run).to render_file(file.name).with_content(default_rewrite_rule)
|
||||
end
|
||||
|
||||
it 'shows the parameterized rewrite rule when http_port is different from 80' do
|
||||
https_port_value = 443
|
||||
node.set['openstack']['dashboard']['http_port'] = 81
|
||||
node.set['openstack']['dashboard']['https_port'] = https_port_value
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(%r(^\s*RewriteRule \^\(\.\*\)\$ https://%\{SERVER_NAME\}:#{https_port_value}%\{REQUEST_URI\} \[L,R\]$))
|
||||
end
|
||||
|
||||
it 'shows the parameterized rewrite rule when https_port is different from 443' do
|
||||
https_port_value = 444
|
||||
node.set['openstack']['dashboard']['http_port'] = 80
|
||||
node.set['openstack']['dashboard']['https_port'] = https_port_value
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(%r(^\s*RewriteRule \^\(\.\*\)\$ https://%\{SERVER_NAME\}:#{https_port_value}%\{REQUEST_URI\} \[L,R\]$))
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows ssl certificate related directives defaults' do
|
||||
[/^\s*SSLEngine on$/,
|
||||
%r(^\s*SSLCertificateFile /etc/ssl/certs/horizon.pem$),
|
||||
%r(^\s*SSLCertificateKeyFile /etc/ssl/private/horizon.key$),
|
||||
/^\s*SSLProtocol All -SSLv2 -SSLv3$/].each do |ssl_certificate_directive|
|
||||
expect(chef_run).to render_file(file.name).with_content(ssl_certificate_directive)
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows ssl certificate related directives overrides' do
|
||||
node.set['openstack']['dashboard']['ssl']['dir'] = 'ssl_dir_value'
|
||||
node.set['openstack']['dashboard']['ssl']['cert'] = 'ssl_cert_value'
|
||||
node.set['openstack']['dashboard']['ssl']['key'] = 'ssl_key_value'
|
||||
node.set['openstack']['dashboard']['ssl']['protocol'] = 'ssl_protocol_value'
|
||||
|
||||
[/^\s*SSLEngine on$/,
|
||||
%r(^\s*SSLCertificateFile ssl_dir_value/certs/ssl_cert_value$),
|
||||
%r(^\s*SSLCertificateKeyFile ssl_dir_value/private/ssl_key_value$),
|
||||
/^\s*SSLProtocol ssl_protocol_value$/].each do |ssl_certificate_directive|
|
||||
expect(chef_run).to render_file(file.name).with_content(ssl_certificate_directive)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with use_ssl disabled' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = false
|
||||
end
|
||||
|
||||
it 'does not show rewrite ssl directive' do
|
||||
expect(chef_run).not_to render_file(file.name).with_content(rewrite_ssl_directive)
|
||||
end
|
||||
|
||||
it 'does not show the default rewrite rule' do
|
||||
node.set['openstack']['dashboard']['http_port'] = 80
|
||||
node.set['openstack']['dashboard']['https_port'] = 443
|
||||
expect(chef_run).not_to render_file(file.name).with_content(default_rewrite_rule)
|
||||
end
|
||||
|
||||
it 'does not show ssl certificate related directives' do
|
||||
[/^\s*SSLEngine on$/,
|
||||
/^\s*SSLCertificateFile/,
|
||||
/^\s*SSLCertificateKeyFile/].each do |ssl_certificate_directive|
|
||||
expect(chef_run).not_to render_file(file.name).with_content(ssl_certificate_directive)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows the ServerAdmin' do
|
||||
node.set['apache']['contact'] = 'apache_contact_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/\s*ServerAdmin apache_contact_value$/)
|
||||
end
|
||||
|
||||
it 'sets the WSGI script alias defaults' do
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(^\s*WSGIScriptAlias / /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi$))
|
||||
end
|
||||
|
||||
it 'sets the WSGI script alias' do
|
||||
node.set['openstack']['dashboard']['wsgi_path'] = 'wsgi_path_value'
|
||||
node.set['openstack']['dashboard']['webroot'] = 'root'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*WSGIScriptAlias root wsgi_path_value$/)
|
||||
end
|
||||
|
||||
it 'sets the WSGI daemon process' do
|
||||
node.set['openstack']['dashboard']['horizon_user'] = 'horizon_user_value'
|
||||
node.set['openstack']['dashboard']['horizon_group'] = 'horizon_group_value'
|
||||
node.set['openstack']['dashboard']['dash_path'] = 'dash_path_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(
|
||||
/^\s*WSGIDaemonProcess dashboard user=horizon_user_value group=horizon_group_value processes=3 threads=10 python-path=dash_path_value$/)
|
||||
end
|
||||
|
||||
it 'has the default DocRoot' do
|
||||
node.set['openstack']['dashboard']['dash_path'] = 'dash_path_value'
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(%r(\s*DocumentRoot dash_path_value/.blackhole/$))
|
||||
end
|
||||
|
||||
it 'has TraceEnable set' do
|
||||
node.set['openstack']['dashboard']['traceenable'] = 'value'
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(/^ TraceEnable value$/)
|
||||
end
|
||||
|
||||
it 'sets the right Alias path for /static' do
|
||||
node.set['openstack']['dashboard']['static_path'] = 'static_path_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s+Alias \/static static_path_value$/)
|
||||
end
|
||||
|
||||
%w(dash_path static_path).each do |dir_attribute|
|
||||
it "sets the #{dir_attribute} directory directive" do
|
||||
node.set['openstack']['dashboard'][dir_attribute] = "#{dir_attribute}_value"
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*<Directory #{dir_attribute}_value>$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'log directives' do
|
||||
before do
|
||||
node.set['apache']['log_dir'] = 'log_dir_value'
|
||||
end
|
||||
|
||||
it 'sets de ErrorLog directive' do
|
||||
node.set['openstack']['dashboard']['error_log'] = 'error_log_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*ErrorLog log_dir_value\/error_log_value$/)
|
||||
end
|
||||
|
||||
it 'sets de CustomLog directive' do
|
||||
node.set['openstack']['dashboard']['access_log'] = 'access_log_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*CustomLog log_dir_value\/access_log_value combined$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets wsgi socket prefix if wsgi_socket_prefix attribute is preset' do
|
||||
node.set['openstack']['dashboard']['wsgi_socket_prefix'] = '/var/run/wsgi'
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(^WSGISocketPrefix /var/run/wsgi$))
|
||||
end
|
||||
|
||||
it 'omits wsgi socket prefix if wsgi_socket_prefix attribute is not preset' do
|
||||
node.set['openstack']['dashboard']['wsgi_socket_prefix'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^WSGISocketPrefix $/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'notifies restore-selinux-context' do
|
||||
expect(file).to notify('execute[restore-selinux-context]').to(:run)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'secret_key_path file' do
|
||||
secret_key_path = '/var/lib/openstack-dashboard/secret_key'
|
||||
let(:file) { chef_run.file(secret_key_path) }
|
||||
|
||||
it 'has correct ownership' do
|
||||
expect(file.owner).to eq('horizon')
|
||||
expect(file.group).to eq('horizon')
|
||||
end
|
||||
|
||||
it 'has correct mode' do
|
||||
expect(file.mode).to eq(00600)
|
||||
end
|
||||
|
||||
it 'does not notify apache2 restart' do
|
||||
expect(file).not_to notify('service[apache2]').to(:restart)
|
||||
end
|
||||
|
||||
it 'has configurable path and ownership settings' do
|
||||
node.set['openstack']['dashboard']['secret_key_path'] = 'somerandompath'
|
||||
node.set['openstack']['dashboard']['horizon_user'] = 'somerandomuser'
|
||||
node.set['openstack']['dashboard']['horizon_group'] = 'somerandomgroup'
|
||||
file = chef_run.file('somerandompath')
|
||||
expect(file.owner).to eq('somerandomuser')
|
||||
expect(file.group).to eq('somerandomgroup')
|
||||
end
|
||||
|
||||
describe 'secret_key_content set' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['secret_key_content'] = 'somerandomcontent'
|
||||
end
|
||||
|
||||
it 'has configurable secret_key_content setting' do
|
||||
expect(chef_run).to render_file(file.name).with_content('somerandomcontent')
|
||||
end
|
||||
|
||||
it 'notifies apache2 restart when secret_key_content set' do
|
||||
expect(file).to notify('service[apache2]').to(:restart)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not delete openstack-dashboard.conf' do
|
||||
file = '/etc/httpd/conf.d/openstack-dashboard.conf'
|
||||
|
||||
expect(chef_run).not_to delete_file(file)
|
||||
end
|
||||
|
||||
it 'calls apache_site to disable 000-default virtualhost' do
|
||||
|
||||
resource = chef_run.find_resource('execute',
|
||||
'a2dissite 000-default').to_hash
|
||||
expect(resource).to include(
|
||||
action: 'run',
|
||||
params: {
|
||||
enable: false,
|
||||
name: '000-default'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'calls apache_site to enable openstack-dashboard virtualhost' do
|
||||
|
||||
resource = chef_run.find_resource('execute',
|
||||
'a2ensite openstack-dashboard').to_hash
|
||||
expect(resource).to include(
|
||||
action: 'run',
|
||||
params: {
|
||||
enable: true,
|
||||
notifies: [:reload, 'service[apache2]', :immediately],
|
||||
name: 'openstack-dashboard'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'notifies apache2 restart' do
|
||||
skip 'TODO: how to test when tied to an LWRP'
|
||||
end
|
||||
|
||||
it 'does not execute restore-selinux-context' do
|
||||
cmd = 'restorecon -Rv /etc/httpd /etc/pki; chcon -R -t httpd_sys_content_t /usr/share/openstack-dashboard || :'
|
||||
|
||||
expect(chef_run).not_to run_execute(cmd)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
# encoding: UTF-8
|
||||
require_relative 'spec_helper'
|
||||
|
||||
describe 'openstack-dashboard::horizon' do
|
||||
|
||||
describe 'redhat' do
|
||||
|
||||
let(:runner) { ChefSpec::Runner.new(REDHAT_OPTS) }
|
||||
let(:node) { runner.node }
|
||||
let(:chef_run) do
|
||||
runner.converge('openstack-dashboard::server')
|
||||
end
|
||||
|
||||
include_context 'dashboard_stubs'
|
||||
include_context 'redhat_stubs'
|
||||
|
||||
it 'installs packages' do
|
||||
expect(chef_run).to upgrade_package('openstack-dashboard')
|
||||
expect(chef_run).to upgrade_package('MySQL-python')
|
||||
end
|
||||
|
||||
it 'installs db2 python packages if explicitly told' do
|
||||
node.set['openstack']['db']['dashboard']['service_type'] = 'db2'
|
||||
%w{python-ibm-db python-ibm-db-django python-ibm-db-sa}.each do |pkg|
|
||||
expect(chef_run).to upgrade_package(pkg)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'local_settings' do
|
||||
let(:file) { chef_run.template('/etc/openstack-dashboard/local_settings') }
|
||||
|
||||
it 'has proper owner' do
|
||||
expect(file.owner).to eq('root')
|
||||
expect(file.group).to eq('apache')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', file.mode)).to eq('640')
|
||||
end
|
||||
|
||||
it 'has urls set' do
|
||||
[
|
||||
%r(^LOGIN_URL = '/auth/login/'$),
|
||||
%r(^LOGOUT_URL = '/auth/logout/'$),
|
||||
/^LOGIN_REDIRECT_URL = '\/'$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not remove openstack-dashboard-ubuntu-theme package' do
|
||||
|
||||
expect(chef_run).not_to purge_package('openstack-dashboard-ubuntu-theme')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +1,14 @@
|
|||
# encoding: UTF-8
|
||||
require_relative 'spec_helper'
|
||||
|
||||
describe 'openstack-dashboard::server' do
|
||||
describe 'openstack-dashboard::horizon' do
|
||||
|
||||
describe 'suse' do
|
||||
|
||||
let(:runner) { ChefSpec::Runner.new(SUSE_OPTS) }
|
||||
let(:node) { runner.node }
|
||||
let(:chef_run) do
|
||||
runner.converge(described_recipe)
|
||||
runner.converge('openstack-dashboard::server')
|
||||
end
|
||||
|
||||
include_context 'non_redhat_stubs'
|
||||
|
@ -54,11 +54,6 @@ describe 'openstack-dashboard::server' do
|
|||
expect(chef_run).to render_file(file.name).with_content('autogenerated')
|
||||
end
|
||||
|
||||
it 'creates .blackhole dir with proper owner' do
|
||||
dir = '/srv/www/openstack-dashboard/openstack_dashboard/.blackhole'
|
||||
expect(chef_run.directory(dir).owner).to eq('root')
|
||||
end
|
||||
|
||||
it 'does not execute openstack-dashboard syncdb by default' do
|
||||
cmd = 'python manage.py syncdb --noinput'
|
||||
expect(chef_run).not_to run_execute(cmd).with(
|
||||
|
@ -71,11 +66,5 @@ describe 'openstack-dashboard::server' do
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'has correct ownership on file with attribute defaults' do
|
||||
file = chef_run.file('/srv/www/openstack-dashboard/openstack_dashboard/local/.secret_key_store')
|
||||
expect(file.owner).to eq('wwwrun')
|
||||
expect(file.group).to eq('www')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,519 @@
|
|||
# encoding: UTF-8
|
||||
require_relative 'spec_helper'
|
||||
|
||||
describe 'openstack-dashboard::horizon' do
|
||||
|
||||
describe 'ubuntu' do
|
||||
|
||||
let(:runner) { ChefSpec::Runner.new(UBUNTU_OPTS) }
|
||||
let(:node) { runner.node }
|
||||
let(:chef_run) do
|
||||
runner.converge('openstack-dashboard::server')
|
||||
end
|
||||
|
||||
let(:chef_run_session_sql) do
|
||||
node.set['openstack']['dashboard']['session_backend'] = 'sql'
|
||||
runner.converge('openstack-dashboard::server')
|
||||
end
|
||||
|
||||
include_context 'non_redhat_stubs'
|
||||
include_context 'dashboard_stubs'
|
||||
|
||||
it 'installs packages' do
|
||||
expect(chef_run).to upgrade_package('lessc')
|
||||
expect(chef_run).to upgrade_package('openstack-dashboard')
|
||||
expect(chef_run).to upgrade_package('python-mysqldb')
|
||||
end
|
||||
|
||||
describe 'local_settings.py' do
|
||||
let(:file) { chef_run.template('/etc/openstack-dashboard/local_settings.py') }
|
||||
|
||||
it 'has proper owner' do
|
||||
expect(file.owner).to eq('root')
|
||||
expect(file.group).to eq('horizon')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', file.mode)).to eq('640')
|
||||
end
|
||||
|
||||
it 'has proper sensitvity' do
|
||||
expect(file.sensitive).to eq(true)
|
||||
end
|
||||
|
||||
context 'template contents' do
|
||||
it 'has the customer banner' do
|
||||
node.set['openstack']['dashboard']['custom_template_banner'] = 'custom_template_banner_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^custom_template_banner_value$/)
|
||||
end
|
||||
|
||||
context 'misc settings' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['misc_local_settings'] = {
|
||||
'CUSTOM_CONFIG_A' => {
|
||||
'variable1' => 'value1',
|
||||
'variable2' => 'value2'
|
||||
},
|
||||
'CUSTOM_CONFIG_B' => {
|
||||
'variable1' => 'value1',
|
||||
'variable2' => 'value2'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'sets misc settings properly' do
|
||||
[
|
||||
['CUSTOM_CONFIG_A = {',
|
||||
' \'variable1\': \'value1\',',
|
||||
' \'variable2\': \'value2\',',
|
||||
'}'],
|
||||
['CUSTOM_CONFIG_B = {',
|
||||
' \'variable1\': \'value1\',',
|
||||
' \'variable2\': \'value2\',',
|
||||
'}']
|
||||
].each do |content|
|
||||
expect(chef_run).to render_file(file.name).with_content(build_section(content))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'debug setting' do
|
||||
context 'set to true' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['debug'] = true
|
||||
end
|
||||
|
||||
it 'has a true value for the DEBUG attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^DEBUG = True$/)
|
||||
end
|
||||
|
||||
it 'sets the console logging level to DEBUG' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'level': 'DEBUG',$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to false' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['debug'] = false
|
||||
end
|
||||
|
||||
it 'has a false value for the DEBUG attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^DEBUG = False$/)
|
||||
end
|
||||
|
||||
it 'sets the console logging level to INFO' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'level': 'INFO',$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'config ssl_no_verify' do
|
||||
context 'set to the default value' do
|
||||
it 'has a True value for the OPENSTACK_SSL_NO_VERIFY attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_SSL_NO_VERIFY = True$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to False' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['ssl_no_verify'] = 'False'
|
||||
end
|
||||
|
||||
it 'has a False value for the OPENSTACK_SSL_NO_VERIFY attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_SSL_NO_VERIFY = False$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'config ssl_cacert' do
|
||||
node.set['openstack']['dashboard']['ssl_cacert'] = '/path_to_cacert.pem'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_SSL_CACERT = '\/path_to_cacert.pem'$/)
|
||||
end
|
||||
|
||||
it 'has some allowed hosts set' do
|
||||
node.set['openstack']['dashboard']['allowed_hosts'] = ['dashboard.example.net']
|
||||
expect(chef_run).to render_file(file.name).with_content(/^ALLOWED_HOSTS = \["dashboard.example.net"\]$/)
|
||||
end
|
||||
|
||||
context 'config hash_algorithm' do
|
||||
context 'set to the default value' do
|
||||
it 'has the default value for the OPENSTACK_TOKEN_HASH_ALGORITHM attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_TOKEN_HASH_ALGORITHM = 'md5'$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to sha256' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['hash_algorithm'] = 'sha256'
|
||||
end
|
||||
|
||||
it 'has a sha256 value for the OPENSTACK_TOKEN_HASH_ALGORITHM attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_TOKEN_HASH_ALGORITHM = 'sha256'$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'ssl offload' do
|
||||
let(:secure_proxy_string) { 'SECURE_PROXY_SSL_HEADER = \(\'HTTP_X_FORWARDED_PROTOCOL\', \'https\'\)' }
|
||||
it 'does not configure ssl proxy when ssl_offload is false' do
|
||||
node.set['openstack']['dashboard']['ssl_offload'] = false
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^#{secure_proxy_string}$/)
|
||||
end
|
||||
|
||||
it 'configures ssl proxy when ssl_offload is set to true' do
|
||||
node.set['openstack']['dashboard']['ssl_offload'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{secure_proxy_string}$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'temp dir override' do
|
||||
context 'temp dir is nil' do
|
||||
it 'does not override temp dir when it is nil' do
|
||||
node.set['openstack']['dashboard']['file_upload_temp_dir'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^FILE_UPLOAD_TEMP_DIR =/)
|
||||
end
|
||||
it 'does override temp dir when it is not nil' do
|
||||
node.set['openstack']['dashboard']['file_upload_temp_dir'] = '/foobar'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^FILE_UPLOAD_TEMP_DIR = "\/foobar"$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'ssl settings' do
|
||||
context 'use_ssl enabled' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = true
|
||||
end
|
||||
|
||||
context 'csrf_cookie_secure setting' do
|
||||
it 'sets secure csrf cookie to true when the attribute is enabled' do
|
||||
node.set['openstack']['dashboard']['csrf_cookie_secure'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^CSRF_COOKIE_SECURE = True$/)
|
||||
end
|
||||
|
||||
it 'sets secure csrf cookie to false when the attribute is disabled' do
|
||||
node.set['openstack']['dashboard']['csrf_cookie_secure'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^CSRF_COOKIE_SECURE = False$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'session_cookie_secure setting' do
|
||||
it 'set secure csrf cookie to true when the sttribute is enabled' do
|
||||
node.set['openstack']['dashboard']['session_cookie_secure'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_COOKIE_SECURE = True$/)
|
||||
end
|
||||
|
||||
it 'set secure csrf cookie to false when the sttribute is disabled' do
|
||||
node.set['openstack']['dashboard']['session_cookie_secure'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_COOKIE_SECURE = False$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not set secure csrf nor secure session cookie settings when use_ssl is disabled' do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = false
|
||||
[/^CSRF_COOKIE_SECURE$/, /^SESSION_COOKIE_SECURE$/].each do |setting|
|
||||
expect(chef_run).not_to render_file(file.name).with_content(setting)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not have urls set' do
|
||||
[
|
||||
/^LOGIN_URL =$/,
|
||||
/^LOGOUT_URL =$/,
|
||||
/^LOGIN_REDIRECT_URL =$/
|
||||
].each do |line|
|
||||
expect(chef_run).to_not render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
|
||||
context 'identity and volume api version setting' do
|
||||
it 'is configurable directly' do
|
||||
node.set['openstack']['dashboard']['identity_api_version'] = 'identity_api_version_value'
|
||||
node.set['openstack']['dashboard']['volume_api_version'] = 'volume_api_version_value'
|
||||
[
|
||||
/^\s*"identity": identity_api_version_value,$/,
|
||||
/^\s*"volume": volume_api_version_value$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the proper value for identity v2.0 with volume default v2 from common attributes' do
|
||||
node.set['openstack']['api']['auth']['version'] = 'v2.0'
|
||||
[
|
||||
/^\s*"identity": 2\.0,$/,
|
||||
/^\s*"volume": 2$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the proper value for identity v3.0 with volume default v2 from common attributes' do
|
||||
node.set['openstack']['api']['auth']['version'] = 'v3.0'
|
||||
[
|
||||
/^\s*"identity": 3,$/,
|
||||
/^\s*"volume": 2$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'keystone multidomain support' do
|
||||
it 'sets to true when the attribute is enabled' do
|
||||
node.set['openstack']['dashboard']['keystone_multidomain_support'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True$/)
|
||||
end
|
||||
|
||||
it 'sets to false when the attribute is disabled' do
|
||||
node.set['openstack']['dashboard']['keystone_multidomain_support'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = False$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'has a keystone default domain setting if identity api version is 3' do
|
||||
node.set['openstack']['dashboard']['identity_api_version'] = 3
|
||||
node.set['openstack']['dashboard']['keystone_default_domain'] = 'keystone_default_domain_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "keystone_default_domain_value"$/)
|
||||
end
|
||||
|
||||
it 'has a console_type setting' do
|
||||
node.set['openstack']['dashboard']['console_type'] = 'console_type_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^CONSOLE_TYPE = "console_type_value"$/)
|
||||
end
|
||||
|
||||
it 'has a help_url setting' do
|
||||
node.set['openstack']['dashboard']['help_url'] = 'help_url_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/\s*'help_url': "help_url_value",$/)
|
||||
end
|
||||
|
||||
context 'simple ip management' do
|
||||
it 'enables the setting when the attribute is set' do
|
||||
node.set['openstack']['dashboard']['simple_ip_management'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content('HORIZON_CONFIG["simple_ip_management"] = True')
|
||||
end
|
||||
|
||||
it 'disables the setting when the attribute is not set' do
|
||||
node.set['openstack']['dashboard']['simple_ip_management'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content('HORIZON_CONFIG["simple_ip_management"] = False')
|
||||
end
|
||||
end
|
||||
|
||||
it 'has default password_autocomplete setting' do
|
||||
node.set['openstack']['dashboard']['password_autocomplete'] = 'password_autocomplete_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^HORIZON_CONFIG\["password_autocomplete"\] = "password_autocomplete_value"$/)
|
||||
end
|
||||
|
||||
it 'has configurable secret_key_path setting' do
|
||||
node.set['openstack']['dashboard']['secret_key_path'] = 'secret_key_path_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SECRET_KEY = secret_key.generate_or_read_from_file\(os.path.realpath\('secret_key_path_value'\)\)$/)
|
||||
end
|
||||
|
||||
context 'session backend' do
|
||||
it 'sets the session engine to file when it is the session backend' do
|
||||
node.set['openstack']['dashboard']['session_backend'] = 'file'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_ENGINE = 'django.contrib.sessions.backends.file'$/)
|
||||
end
|
||||
|
||||
context 'memcached as session backend' do
|
||||
let(:memcached_session_engine_setting) { /^SESSION_ENGINE = 'django.contrib.sessions.backends.cache'$/ }
|
||||
context 'with memcache servers' do
|
||||
it 'sets the session engine attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(memcached_session_engine_setting)
|
||||
end
|
||||
|
||||
it 'sets the location of the caches to the memcached servers addresses' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'LOCATION': \[\s*'hostA:port',\s*'hostB:port',\s*\]$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without memcache servers' do
|
||||
[nil, []].each do |empty_value|
|
||||
it "does not configure caching when backend == memcache and #{empty_value} provided as memcache servers" do
|
||||
allow_any_instance_of(Chef::Recipe).to receive(:memcached_servers)
|
||||
.and_return(empty_value)
|
||||
|
||||
expect(chef_run).not_to render_file(file.name)
|
||||
.with_content(memcached_session_engine_setting)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the session engine to db when sql is the session backend' do
|
||||
node.set['openstack']['dashboard']['session_backend'] = 'sql'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_ENGINE = 'django.contrib.sessions.backends.db'$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'has a keystone url' do
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(OPENSTACK_KEYSTONE_URL = "http://127.0.0.1:5000/v2.0"))
|
||||
end
|
||||
|
||||
it 'has a keystone admin url' do
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(OPENSTACK_KEYSTONE_ADMIN_URL = "http://127.0.0.1:35357/v2.0"))
|
||||
end
|
||||
|
||||
it 'has a keystone default role' do
|
||||
node.set['openstack']['dashboard']['keystone_default_role'] = 'keystone_default_role_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_DEFAULT_ROLE = "keystone_default_role_value"$/)
|
||||
end
|
||||
|
||||
context 'keystone_backend settings' do
|
||||
%w(native ldap).each do |keystone_backend_name|
|
||||
it "sets the backend name to #{keystone_backend_name}" do
|
||||
node.set['openstack']['dashboard']['keystone_backend']['name'] = keystone_backend_name
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'name': '#{keystone_backend_name}',$/)
|
||||
end
|
||||
end
|
||||
|
||||
%w(can_edit_user can_edit_group can_edit_project can_edit_domain can_edit_role).each do |keystone_setting|
|
||||
it "enables the #{keystone_setting} keystone backend setting when the attribute is True" do
|
||||
node.set['openstack']['dashboard']['keystone_backend'][keystone_setting] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{keystone_setting}\': True,$/)
|
||||
end
|
||||
|
||||
it "disables the #{keystone_setting} keystone backend setting when the attribute is False" do
|
||||
node.set['openstack']['dashboard']['keystone_backend'][keystone_setting] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{keystone_setting}\': False,$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'neutron settings' do
|
||||
%w(enable_lb enable_quotas enable_firewall enable_vpn).each do |neutron_setting|
|
||||
it "enables the #{neutron_setting} setting when the attributes is True" do
|
||||
node.set['openstack']['dashboard']['neutron'][neutron_setting] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{neutron_setting}\': True,$/)
|
||||
end
|
||||
|
||||
it "disables the #{neutron_setting} setting when the attributes is False" do
|
||||
node.set['openstack']['dashboard']['neutron'][neutron_setting] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{neutron_setting}\': False,$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%w(horizon openstack_dashboard novaclient cinderclient keystoneclient
|
||||
glanceclient neutronclient heatclient ceilometerclient troveclient
|
||||
swiftclient openstack_auth nose.plugins.manager django).each do |component|
|
||||
it "sets the logger level for #{component}" do
|
||||
node.set['openstack']['dashboard']['log_level'][component] = "#{component}_log_level_value"
|
||||
expect(chef_run).to render_file(file.name).with_content(
|
||||
/^\s*'#{component}': {\s*'handlers': \['console'\],\s*'level': '#{component}_log_level_value',$/)
|
||||
end
|
||||
end
|
||||
|
||||
{ 'mysql' => 'django.db.backends.mysql',
|
||||
'sqlite' => 'django.db.backends.sqlite3',
|
||||
'postgresql' => 'django.db.backends.postgresql_psycopg2',
|
||||
'db2' => 'ibm_db_django' }.each do |service_type, backend|
|
||||
context "#{service_type} database settings" do
|
||||
before do
|
||||
allow_any_instance_of(Chef::Recipe).to receive(:db)
|
||||
.with('dashboard')
|
||||
.and_return('service_type' => service_type,
|
||||
'db_name' => "#{service_type}_db",
|
||||
'host' => "#{service_type}_host")
|
||||
node.set['openstack']['db']['dashboard']['username'] = "#{service_type}_user"
|
||||
node.set['openstack']['db']['python_packages'][service_type] = ['pkg1', 'pkg2']
|
||||
end
|
||||
|
||||
[/^\s*'ENGINE': '#{backend}',$/,
|
||||
/^\s*'NAME': '#{service_type}_db',$/].each do |cfg|
|
||||
it "configures the #{service_type} backend with #{cfg}" do
|
||||
expect(chef_run).to render_file(file.name).with_content(cfg)
|
||||
end
|
||||
end
|
||||
|
||||
[/^\s*'USER': '#{service_type}_user',$/,
|
||||
/^\s*'PASSWORD': 'test-passes',$/,
|
||||
/^\s*'HOST': '#{service_type}_host',$/].each do |cfg|
|
||||
unless service_type == 'sqlite'
|
||||
it "configures the #{service_type} backend with #{cfg}" do
|
||||
expect(chef_run).to render_file(file.name).with_content(cfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'plugins' do
|
||||
let(:mod_regex) { /^mod = sys.modules\['openstack_dashboard.settings'\]$/ }
|
||||
context 'plugins enabled' do
|
||||
let(:plugins) { %w(testPlugin1 testPlugin2) }
|
||||
before do
|
||||
node.set['openstack']['dashboard']['plugins'] = plugins
|
||||
end
|
||||
|
||||
it 'shows the mod setting' do
|
||||
expect(chef_run).to render_file(file.name).with_content(mod_regex)
|
||||
end
|
||||
|
||||
it 'shows enabled plugins as installed apps' do
|
||||
plugins.each do |plugin|
|
||||
expect(chef_run).to render_file(file.name).with_content(/^mod\.INSTALLED_APPS \+= \('#{plugin}', \)$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not show the mod setting if there are no plugins' do
|
||||
node.set['openstack']['dashboard']['plugins'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(mod_regex)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'openstack-dashboard syncdb' do
|
||||
sync_db_cmd = 'python manage.py syncdb --noinput'
|
||||
sync_db_environment = {
|
||||
'PYTHONPATH' => '/etc/openstack-dashboard:' \
|
||||
'/usr/share/openstack-dashboard:' \
|
||||
'$PYTHONPATH'
|
||||
}
|
||||
|
||||
it 'does not execute when session_backend is not sql' do
|
||||
expect(chef_run).not_to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
|
||||
it 'executes when session_backend is sql' do
|
||||
expect(chef_run_session_sql).to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not execute when the migrate attribute is set to false' do
|
||||
node.set['openstack']['db']['dashboard']['migrate'] = false
|
||||
expect(chef_run_session_sql).not_to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
|
||||
it 'executes when database backend is sqlite' do
|
||||
node.set['openstack']['db']['dashboard']['service_type'] = 'sqlite'
|
||||
expect(chef_run_session_sql).to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'removes openstack-dashboard-ubuntu-theme package' do
|
||||
expect(chef_run).to purge_package('openstack-dashboard-ubuntu-theme')
|
||||
end
|
||||
|
||||
it 'has group write mode on path' do
|
||||
path = chef_run.directory("#{chef_run.node['openstack']['dashboard']['dash_path']}/local")
|
||||
expect(path.mode).to eq(02770)
|
||||
expect(path.group).to eq(chef_run.node['openstack']['dashboard']['horizon_group'])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,905 +1,23 @@
|
|||
# encoding: UTF-8
|
||||
require_relative 'spec_helper'
|
||||
|
||||
shared_examples 'virtualhost port configurator' do |port_attribute_name, port_attribute_value|
|
||||
let(:virtualhost_directive) { "<VirtualHost \\*:#{port_attribute_value}>" }
|
||||
before do
|
||||
node.set['openstack']['dashboard'][port_attribute_name] = port_attribute_value
|
||||
end
|
||||
|
||||
it "sets Listen and NameVirtualHost directives when apache's listen_ports does not include #{port_attribute_value}" do
|
||||
node.set['apache']['listen_ports'] = [port_attribute_value.to_i + 1]
|
||||
%w(Listen NameVirtualHost).each do |directive|
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{directive} \*:#{port_attribute_value}$/)
|
||||
end
|
||||
end
|
||||
|
||||
it "does not set Listen and NameVirtualHost directives when apache's listen_ports include #{port_attribute_value}" do
|
||||
node.set['apache']['listen_ports'] = [port_attribute_value]
|
||||
chef_run.converge(described_recipe)
|
||||
%w(Listen NameVirtualHost).each do |directive|
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^#{directive} \*:#{port_attribute_value}$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the VirtualHost directive' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{virtualhost_directive}$/)
|
||||
end
|
||||
|
||||
context 'server_hostname' do
|
||||
it 'sets the value if the server_hostname is present' do
|
||||
node.set['openstack']['dashboard']['server_hostname'] = 'server_hostname_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{virtualhost_directive}\s*ServerName server_hostname_value$/)
|
||||
end
|
||||
|
||||
it 'does not set the value if the server_hostname is not present' do
|
||||
node.set['openstack']['dashboard']['server_hostname'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^#{virtualhost_directive}\s*ServerName$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'openstack-dashboard::server' do
|
||||
|
||||
describe 'ubuntu' do
|
||||
|
||||
let(:runner) { ChefSpec::Runner.new(UBUNTU_OPTS) }
|
||||
let(:node) { runner.node }
|
||||
let(:chef_run) do
|
||||
runner.converge(described_recipe)
|
||||
end
|
||||
|
||||
let(:chef_run_session_sql) do
|
||||
node.set['openstack']['dashboard']['session_backend'] = 'sql'
|
||||
runner.converge(described_recipe)
|
||||
end
|
||||
|
||||
include_context 'non_redhat_stubs'
|
||||
include_context 'dashboard_stubs'
|
||||
|
||||
it 'does not execute set-selinux-permissive' do
|
||||
cmd = '/sbin/setenforce Permissive'
|
||||
expect(chef_run).not_to run_execute(cmd)
|
||||
end
|
||||
|
||||
it 'installs apache packages' do
|
||||
expect(chef_run).to include_recipe('apache2')
|
||||
expect(chef_run).to include_recipe('apache2::mod_wsgi')
|
||||
expect(chef_run).to include_recipe('apache2::mod_rewrite')
|
||||
expect(chef_run).to include_recipe('apache2::mod_ssl')
|
||||
end
|
||||
|
||||
it 'does not execute set-selinux-enforcing' do
|
||||
cmd = '/sbin/setenforce Enforcing ; restorecon -R /etc/httpd'
|
||||
expect(chef_run).not_to run_execute(cmd)
|
||||
end
|
||||
|
||||
it 'installs packages' do
|
||||
expect(chef_run).to upgrade_package('lessc')
|
||||
expect(chef_run).to upgrade_package('openstack-dashboard')
|
||||
expect(chef_run).to upgrade_package('python-mysqldb')
|
||||
end
|
||||
|
||||
describe 'local_settings.py' do
|
||||
let(:file) { chef_run.template('/etc/openstack-dashboard/local_settings.py') }
|
||||
|
||||
it 'has proper owner' do
|
||||
expect(file.owner).to eq('root')
|
||||
expect(file.group).to eq('horizon')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', file.mode)).to eq('640')
|
||||
end
|
||||
|
||||
it 'has proper sensitvity' do
|
||||
expect(file.sensitive).to eq(true)
|
||||
end
|
||||
|
||||
context 'template contents' do
|
||||
it 'has the customer banner' do
|
||||
node.set['openstack']['dashboard']['custom_template_banner'] = 'custom_template_banner_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^custom_template_banner_value$/)
|
||||
end
|
||||
|
||||
context 'misc settings' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['misc_local_settings'] = {
|
||||
'CUSTOM_CONFIG_A' => {
|
||||
'variable1' => 'value1',
|
||||
'variable2' => 'value2'
|
||||
},
|
||||
'CUSTOM_CONFIG_B' => {
|
||||
'variable1' => 'value1',
|
||||
'variable2' => 'value2'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'sets misc settings properly' do
|
||||
[
|
||||
['CUSTOM_CONFIG_A = {',
|
||||
' \'variable1\': \'value1\',',
|
||||
' \'variable2\': \'value2\',',
|
||||
'}'],
|
||||
['CUSTOM_CONFIG_B = {',
|
||||
' \'variable1\': \'value1\',',
|
||||
' \'variable2\': \'value2\',',
|
||||
'}']
|
||||
].each do |content|
|
||||
expect(chef_run).to render_file(file.name).with_content(build_section(content))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'debug setting' do
|
||||
context 'set to true' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['debug'] = true
|
||||
end
|
||||
|
||||
it 'has a true value for the DEBUG attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^DEBUG = True$/)
|
||||
end
|
||||
|
||||
it 'sets the console logging level to DEBUG' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'level': 'DEBUG',$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to false' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['debug'] = false
|
||||
end
|
||||
|
||||
it 'has a false value for the DEBUG attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^DEBUG = False$/)
|
||||
end
|
||||
|
||||
it 'sets the console logging level to INFO' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'level': 'INFO',$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'config ssl_no_verify' do
|
||||
context 'set to the default value' do
|
||||
it 'has a True value for the OPENSTACK_SSL_NO_VERIFY attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_SSL_NO_VERIFY = True$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to False' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['ssl_no_verify'] = 'False'
|
||||
end
|
||||
|
||||
it 'has a False value for the OPENSTACK_SSL_NO_VERIFY attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_SSL_NO_VERIFY = False$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'config ssl_cacert' do
|
||||
node.set['openstack']['dashboard']['ssl_cacert'] = '/path_to_cacert.pem'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_SSL_CACERT = '\/path_to_cacert.pem'$/)
|
||||
end
|
||||
|
||||
it 'has some allowed hosts set' do
|
||||
node.set['openstack']['dashboard']['allowed_hosts'] = ['dashboard.example.net']
|
||||
expect(chef_run).to render_file(file.name).with_content(/^ALLOWED_HOSTS = \["dashboard.example.net"\]$/)
|
||||
end
|
||||
|
||||
context 'config hash_algorithm' do
|
||||
context 'set to the default value' do
|
||||
it 'has the default value for the OPENSTACK_TOKEN_HASH_ALGORITHM attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_TOKEN_HASH_ALGORITHM = 'md5'$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to sha256' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['hash_algorithm'] = 'sha256'
|
||||
end
|
||||
|
||||
it 'has a sha256 value for the OPENSTACK_TOKEN_HASH_ALGORITHM attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_TOKEN_HASH_ALGORITHM = 'sha256'$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'ssl offload' do
|
||||
let(:secure_proxy_string) { 'SECURE_PROXY_SSL_HEADER = \(\'HTTP_X_FORWARDED_PROTOCOL\', \'https\'\)' }
|
||||
it 'does not configure ssl proxy when ssl_offload is false' do
|
||||
node.set['openstack']['dashboard']['ssl_offload'] = false
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^#{secure_proxy_string}$/)
|
||||
end
|
||||
|
||||
it 'configures ssl proxy when ssl_offload is set to true' do
|
||||
node.set['openstack']['dashboard']['ssl_offload'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^#{secure_proxy_string}$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'temp dir override' do
|
||||
context 'temp dir is nil' do
|
||||
it 'does not override temp dir when it is nil' do
|
||||
node.set['openstack']['dashboard']['file_upload_temp_dir'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^FILE_UPLOAD_TEMP_DIR =/)
|
||||
end
|
||||
it 'does override temp dir when it is not nil' do
|
||||
node.set['openstack']['dashboard']['file_upload_temp_dir'] = '/foobar'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^FILE_UPLOAD_TEMP_DIR = "\/foobar"$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'ssl settings' do
|
||||
context 'use_ssl enabled' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = true
|
||||
end
|
||||
|
||||
context 'csrf_cookie_secure setting' do
|
||||
it 'sets secure csrf cookie to true when the attribute is enabled' do
|
||||
node.set['openstack']['dashboard']['csrf_cookie_secure'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^CSRF_COOKIE_SECURE = True$/)
|
||||
end
|
||||
|
||||
it 'sets secure csrf cookie to false when the attribute is disabled' do
|
||||
node.set['openstack']['dashboard']['csrf_cookie_secure'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^CSRF_COOKIE_SECURE = False$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'session_cookie_secure setting' do
|
||||
it 'set secure csrf cookie to true when the sttribute is enabled' do
|
||||
node.set['openstack']['dashboard']['session_cookie_secure'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_COOKIE_SECURE = True$/)
|
||||
end
|
||||
|
||||
it 'set secure csrf cookie to false when the sttribute is disabled' do
|
||||
node.set['openstack']['dashboard']['session_cookie_secure'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_COOKIE_SECURE = False$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not set secure csrf nor secure session cookie settings when use_ssl is disabled' do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = false
|
||||
[/^CSRF_COOKIE_SECURE$/, /^SESSION_COOKIE_SECURE$/].each do |setting|
|
||||
expect(chef_run).not_to render_file(file.name).with_content(setting)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not have urls set' do
|
||||
[
|
||||
/^LOGIN_URL =$/,
|
||||
/^LOGOUT_URL =$/,
|
||||
/^LOGIN_REDIRECT_URL =$/
|
||||
].each do |line|
|
||||
expect(chef_run).to_not render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
|
||||
context 'identity and volume api version setting' do
|
||||
it 'is configurable directly' do
|
||||
node.set['openstack']['dashboard']['identity_api_version'] = 'identity_api_version_value'
|
||||
node.set['openstack']['dashboard']['volume_api_version'] = 'volume_api_version_value'
|
||||
[
|
||||
/^\s*"identity": identity_api_version_value,$/,
|
||||
/^\s*"volume": volume_api_version_value$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the proper value for identity v2.0 with volume default v2 from common attributes' do
|
||||
node.set['openstack']['api']['auth']['version'] = 'v2.0'
|
||||
[
|
||||
/^\s*"identity": 2\.0,$/,
|
||||
/^\s*"volume": 2$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the proper value for identity v3.0 with volume default v2 from common attributes' do
|
||||
node.set['openstack']['api']['auth']['version'] = 'v3.0'
|
||||
[
|
||||
/^\s*"identity": 3,$/,
|
||||
/^\s*"volume": 2$/
|
||||
].each do |line|
|
||||
expect(chef_run).to render_file(file.name).with_content(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'keystone multidomain support' do
|
||||
it 'sets to true when the attribute is enabled' do
|
||||
node.set['openstack']['dashboard']['keystone_multidomain_support'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True$/)
|
||||
end
|
||||
|
||||
it 'sets to false when the attribute is disabled' do
|
||||
node.set['openstack']['dashboard']['keystone_multidomain_support'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = False$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'has a keystone default domain setting if identity api version is 3' do
|
||||
node.set['openstack']['dashboard']['identity_api_version'] = 3
|
||||
node.set['openstack']['dashboard']['keystone_default_domain'] = 'keystone_default_domain_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "keystone_default_domain_value"$/)
|
||||
end
|
||||
|
||||
it 'has a console_type setting' do
|
||||
node.set['openstack']['dashboard']['console_type'] = 'console_type_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^CONSOLE_TYPE = "console_type_value"$/)
|
||||
end
|
||||
|
||||
it 'has a help_url setting' do
|
||||
node.set['openstack']['dashboard']['help_url'] = 'help_url_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/\s*'help_url': "help_url_value",$/)
|
||||
end
|
||||
|
||||
context 'simple ip management' do
|
||||
it 'enables the setting when the attribute is set' do
|
||||
node.set['openstack']['dashboard']['simple_ip_management'] = true
|
||||
expect(chef_run).to render_file(file.name).with_content('HORIZON_CONFIG["simple_ip_management"] = True')
|
||||
end
|
||||
|
||||
it 'disables the setting when the attribute is not set' do
|
||||
node.set['openstack']['dashboard']['simple_ip_management'] = false
|
||||
expect(chef_run).to render_file(file.name).with_content('HORIZON_CONFIG["simple_ip_management"] = False')
|
||||
end
|
||||
end
|
||||
|
||||
it 'has default password_autocomplete setting' do
|
||||
node.set['openstack']['dashboard']['password_autocomplete'] = 'password_autocomplete_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^HORIZON_CONFIG\["password_autocomplete"\] = "password_autocomplete_value"$/)
|
||||
end
|
||||
|
||||
it 'has configurable secret_key_path setting' do
|
||||
node.set['openstack']['dashboard']['secret_key_path'] = 'secret_key_path_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SECRET_KEY = secret_key.generate_or_read_from_file\(os.path.realpath\('secret_key_path_value'\)\)$/)
|
||||
end
|
||||
|
||||
context 'session backend' do
|
||||
it 'sets the session engine to file when it is the session backend' do
|
||||
node.set['openstack']['dashboard']['session_backend'] = 'file'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_ENGINE = 'django.contrib.sessions.backends.file'$/)
|
||||
end
|
||||
|
||||
context 'memcached as session backend' do
|
||||
let(:memcached_session_engine_setting) { /^SESSION_ENGINE = 'django.contrib.sessions.backends.cache'$/ }
|
||||
context 'with memcache servers' do
|
||||
it 'sets the session engine attribute' do
|
||||
expect(chef_run).to render_file(file.name).with_content(memcached_session_engine_setting)
|
||||
end
|
||||
|
||||
it 'sets the location of the caches to the memcached servers addresses' do
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'LOCATION': \[\s*'hostA:port',\s*'hostB:port',\s*\]$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without memcache servers' do
|
||||
[nil, []].each do |empty_value|
|
||||
it "does not configure caching when backend == memcache and #{empty_value} provided as memcache servers" do
|
||||
allow_any_instance_of(Chef::Recipe).to receive(:memcached_servers)
|
||||
.and_return(empty_value)
|
||||
|
||||
expect(chef_run).not_to render_file(file.name)
|
||||
.with_content(memcached_session_engine_setting)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the session engine to db when sql is the session backend' do
|
||||
node.set['openstack']['dashboard']['session_backend'] = 'sql'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^SESSION_ENGINE = 'django.contrib.sessions.backends.db'$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'has a keystone url' do
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(OPENSTACK_KEYSTONE_URL = "http://127.0.0.1:5000/v2.0"))
|
||||
end
|
||||
|
||||
it 'has a keystone admin url' do
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(OPENSTACK_KEYSTONE_ADMIN_URL = "http://127.0.0.1:35357/v2.0"))
|
||||
end
|
||||
|
||||
it 'has a keystone default role' do
|
||||
node.set['openstack']['dashboard']['keystone_default_role'] = 'keystone_default_role_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^OPENSTACK_KEYSTONE_DEFAULT_ROLE = "keystone_default_role_value"$/)
|
||||
end
|
||||
|
||||
context 'keystone_backend settings' do
|
||||
%w(native ldap).each do |keystone_backend_name|
|
||||
it "sets the backend name to #{keystone_backend_name}" do
|
||||
node.set['openstack']['dashboard']['keystone_backend']['name'] = keystone_backend_name
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*'name': '#{keystone_backend_name}',$/)
|
||||
end
|
||||
end
|
||||
|
||||
%w(can_edit_user can_edit_group can_edit_project can_edit_domain can_edit_role).each do |keystone_setting|
|
||||
it "enables the #{keystone_setting} keystone backend setting when the attribute is True" do
|
||||
node.set['openstack']['dashboard']['keystone_backend'][keystone_setting] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{keystone_setting}\': True,$/)
|
||||
end
|
||||
|
||||
it "disables the #{keystone_setting} keystone backend setting when the attribute is False" do
|
||||
node.set['openstack']['dashboard']['keystone_backend'][keystone_setting] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{keystone_setting}\': False,$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'neutron settings' do
|
||||
%w(enable_lb enable_quotas enable_firewall enable_vpn).each do |neutron_setting|
|
||||
it "enables the #{neutron_setting} setting when the attributes is True" do
|
||||
node.set['openstack']['dashboard']['neutron'][neutron_setting] = true
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{neutron_setting}\': True,$/)
|
||||
end
|
||||
|
||||
it "disables the #{neutron_setting} setting when the attributes is False" do
|
||||
node.set['openstack']['dashboard']['neutron'][neutron_setting] = false
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*\'#{neutron_setting}\': False,$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%w(horizon openstack_dashboard novaclient cinderclient keystoneclient
|
||||
glanceclient neutronclient heatclient ceilometerclient troveclient
|
||||
swiftclient openstack_auth nose.plugins.manager django).each do |component|
|
||||
it "sets the logger level for #{component}" do
|
||||
node.set['openstack']['dashboard']['log_level'][component] = "#{component}_log_level_value"
|
||||
expect(chef_run).to render_file(file.name).with_content(
|
||||
/^\s*'#{component}': {\s*'handlers': \['console'\],\s*'level': '#{component}_log_level_value',$/)
|
||||
end
|
||||
end
|
||||
|
||||
{ 'mysql' => 'django.db.backends.mysql',
|
||||
'sqlite' => 'django.db.backends.sqlite3',
|
||||
'postgresql' => 'django.db.backends.postgresql_psycopg2',
|
||||
'db2' => 'ibm_db_django' }.each do |service_type, backend|
|
||||
context "#{service_type} database settings" do
|
||||
before do
|
||||
allow_any_instance_of(Chef::Recipe).to receive(:db)
|
||||
.with('dashboard')
|
||||
.and_return('service_type' => service_type,
|
||||
'db_name' => "#{service_type}_db",
|
||||
'host' => "#{service_type}_host")
|
||||
node.set['openstack']['db']['dashboard']['username'] = "#{service_type}_user"
|
||||
node.set['openstack']['db']['python_packages'][service_type] = ['pkg1', 'pkg2']
|
||||
end
|
||||
|
||||
[/^\s*'ENGINE': '#{backend}',$/,
|
||||
/^\s*'NAME': '#{service_type}_db',$/].each do |cfg|
|
||||
it "configures the #{service_type} backend with #{cfg}" do
|
||||
expect(chef_run).to render_file(file.name).with_content(cfg)
|
||||
end
|
||||
end
|
||||
|
||||
[/^\s*'USER': '#{service_type}_user',$/,
|
||||
/^\s*'PASSWORD': 'test-passes',$/,
|
||||
/^\s*'HOST': '#{service_type}_host',$/].each do |cfg|
|
||||
unless service_type == 'sqlite'
|
||||
it "configures the #{service_type} backend with #{cfg}" do
|
||||
expect(chef_run).to render_file(file.name).with_content(cfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'plugins' do
|
||||
let(:mod_regex) { /^mod = sys.modules\['openstack_dashboard.settings'\]$/ }
|
||||
context 'plugins enabled' do
|
||||
let(:plugins) { %w(testPlugin1 testPlugin2) }
|
||||
before do
|
||||
node.set['openstack']['dashboard']['plugins'] = plugins
|
||||
end
|
||||
|
||||
it 'shows the mod setting' do
|
||||
expect(chef_run).to render_file(file.name).with_content(mod_regex)
|
||||
end
|
||||
|
||||
it 'shows enabled plugins as installed apps' do
|
||||
plugins.each do |plugin|
|
||||
expect(chef_run).to render_file(file.name).with_content(/^mod\.INSTALLED_APPS \+= \('#{plugin}', \)$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not show the mod setting if there are no plugins' do
|
||||
node.set['openstack']['dashboard']['plugins'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(mod_regex)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'notifies apache2 restart' do
|
||||
expect(file).to notify('service[apache2]').to(:restart)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'openstack-dashboard syncdb' do
|
||||
sync_db_cmd = 'python manage.py syncdb --noinput'
|
||||
sync_db_environment = {
|
||||
'PYTHONPATH' => '/etc/openstack-dashboard:' \
|
||||
'/usr/share/openstack-dashboard:' \
|
||||
'$PYTHONPATH'
|
||||
}
|
||||
|
||||
it 'does not execute when session_backend is not sql' do
|
||||
expect(chef_run).not_to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
|
||||
it 'executes when session_backend is sql' do
|
||||
expect(chef_run_session_sql).to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not execute when the migrate attribute is set to false' do
|
||||
node.set['openstack']['db']['dashboard']['migrate'] = false
|
||||
expect(chef_run_session_sql).not_to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
|
||||
it 'executes when database backend is sqlite' do
|
||||
node.set['openstack']['db']['dashboard']['service_type'] = 'sqlite'
|
||||
expect(chef_run_session_sql).to run_execute(sync_db_cmd).with(
|
||||
cwd: node['openstack']['dashboard']['django_path'],
|
||||
environment: sync_db_environment
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'certs' do
|
||||
let(:crt) { chef_run.cookbook_file('/etc/ssl/certs/horizon.pem') }
|
||||
let(:key) { chef_run.cookbook_file('/etc/ssl/private/horizon.key') }
|
||||
let(:remote_key) { chef_run.remote_file('/etc/ssl/private/horizon.key') }
|
||||
|
||||
it 'has proper owner and group' do
|
||||
expect(crt.owner).to eq('root')
|
||||
expect(crt.group).to eq('root')
|
||||
expect(key.owner).to eq('root')
|
||||
expect(key.group).to eq('ssl-cert')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', crt.mode)).to eq('644')
|
||||
expect(sprintf('%o', key.mode)).to eq('640')
|
||||
end
|
||||
|
||||
it 'has proper sensitvity' do
|
||||
expect(crt.sensitive).to eq(true)
|
||||
expect(key.sensitive).to eq(true)
|
||||
end
|
||||
|
||||
it 'notifies restore-selinux-context' do
|
||||
expect(crt).to notify('execute[restore-selinux-context]').to(:run)
|
||||
expect(key).to notify('execute[restore-selinux-context]').to(:run)
|
||||
end
|
||||
|
||||
it 'does not download certs if not needed' do
|
||||
expect(chef_run).not_to create_remote_file('/etc/ssl/certs/horizon.pem')
|
||||
expect(chef_run).not_to create_remote_file('/etc/ssl/private/horizon.key')
|
||||
end
|
||||
|
||||
it 'downloads certs if needed and restarts apache' do
|
||||
node.set['openstack']['dashboard']['ssl']['cert_url'] = 'http://server/mycert.pem'
|
||||
node.set['openstack']['dashboard']['ssl']['key_url'] = 'http://server/mykey.key'
|
||||
expect(chef_run).to create_remote_file('/etc/ssl/certs/horizon.pem').with(
|
||||
sensitive: true,
|
||||
user: 'root',
|
||||
group: 'root',
|
||||
mode: 0644
|
||||
)
|
||||
expect(chef_run).to create_remote_file('/etc/ssl/private/horizon.key').with(
|
||||
sensitive: true,
|
||||
user: 'root',
|
||||
group: 'ssl-cert',
|
||||
mode: 0640
|
||||
)
|
||||
expect(remote_key).to notify('service[apache2]').to(:restart)
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates .blackhole dir with proper owner' do
|
||||
dir = '/usr/share/openstack-dashboard/openstack_dashboard/.blackhole'
|
||||
|
||||
expect(chef_run.directory(dir).owner).to eq('root')
|
||||
end
|
||||
|
||||
describe 'openstack-dashboard virtual host' do
|
||||
let(:file) { chef_run.template('/etc/apache2/sites-available/openstack-dashboard') }
|
||||
|
||||
it 'has proper owner' do
|
||||
expect(file.owner).to eq('root')
|
||||
expect(file.group).to eq('root')
|
||||
end
|
||||
|
||||
it 'has proper modes' do
|
||||
expect(sprintf('%o', file.mode)).to eq('644')
|
||||
end
|
||||
|
||||
context 'template content' do
|
||||
let(:rewrite_ssl_directive) { /^\s*RewriteEngine On\s*RewriteCond \%\{HTTPS\} off$/ }
|
||||
let(:default_rewrite_rule) { %r(^\s*RewriteRule \^\(\.\*\)\$ https\://%\{HTTP_HOST\}%\{REQUEST_URI\} \[L,R\]$) }
|
||||
|
||||
it 'has the default banner' do
|
||||
node.set['openstack']['dashboard']['custom_template_banner'] = 'custom_template_banner_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^custom_template_banner_value$/)
|
||||
end
|
||||
|
||||
it_should_behave_like 'virtualhost port configurator', 'http_port', 8080
|
||||
|
||||
context 'with use_ssl enabled' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = true
|
||||
end
|
||||
|
||||
it_should_behave_like 'virtualhost port configurator', 'https_port', 4433
|
||||
|
||||
it 'shows rewrite ssl directive' do
|
||||
expect(chef_run).to render_file(file.name).with_content(rewrite_ssl_directive)
|
||||
end
|
||||
|
||||
context 'rewrite rule' do
|
||||
it 'shows the default rewrite rule when http_port is 80 and https_port is 443' do
|
||||
node.set['openstack']['dashboard']['http_port'] = 80
|
||||
node.set['openstack']['dashboard']['https_port'] = 443
|
||||
expect(chef_run).to render_file(file.name).with_content(default_rewrite_rule)
|
||||
end
|
||||
|
||||
it 'shows the parameterized rewrite rule when http_port is different from 80' do
|
||||
https_port_value = 443
|
||||
node.set['openstack']['dashboard']['http_port'] = 81
|
||||
node.set['openstack']['dashboard']['https_port'] = https_port_value
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(%r(^\s*RewriteRule \^\(\.\*\)\$ https://%\{SERVER_NAME\}:#{https_port_value}%\{REQUEST_URI\} \[L,R\]$))
|
||||
end
|
||||
|
||||
it 'shows the parameterized rewrite rule when https_port is different from 443' do
|
||||
https_port_value = 444
|
||||
node.set['openstack']['dashboard']['http_port'] = 80
|
||||
node.set['openstack']['dashboard']['https_port'] = https_port_value
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(%r(^\s*RewriteRule \^\(\.\*\)\$ https://%\{SERVER_NAME\}:#{https_port_value}%\{REQUEST_URI\} \[L,R\]$))
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows ssl certificate related directives defaults' do
|
||||
[/^\s*SSLEngine on$/,
|
||||
%r(^\s*SSLCertificateFile /etc/ssl/certs/horizon.pem$),
|
||||
%r(^\s*SSLCertificateKeyFile /etc/ssl/private/horizon.key$),
|
||||
/^\s*SSLProtocol All -SSLv2 -SSLv3$/].each do |ssl_certificate_directive|
|
||||
expect(chef_run).to render_file(file.name).with_content(ssl_certificate_directive)
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows ssl certificate related directives overrides' do
|
||||
node.set['openstack']['dashboard']['ssl']['dir'] = 'ssl_dir_value'
|
||||
node.set['openstack']['dashboard']['ssl']['cert'] = 'ssl_cert_value'
|
||||
node.set['openstack']['dashboard']['ssl']['key'] = 'ssl_key_value'
|
||||
node.set['openstack']['dashboard']['ssl']['protocol'] = 'ssl_protocol_value'
|
||||
|
||||
[/^\s*SSLEngine on$/,
|
||||
%r(^\s*SSLCertificateFile ssl_dir_value/certs/ssl_cert_value$),
|
||||
%r(^\s*SSLCertificateKeyFile ssl_dir_value/private/ssl_key_value$),
|
||||
/^\s*SSLProtocol ssl_protocol_value$/].each do |ssl_certificate_directive|
|
||||
expect(chef_run).to render_file(file.name).with_content(ssl_certificate_directive)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with use_ssl disabled' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['use_ssl'] = false
|
||||
end
|
||||
|
||||
it 'does not show rewrite ssl directive' do
|
||||
expect(chef_run).not_to render_file(file.name).with_content(rewrite_ssl_directive)
|
||||
end
|
||||
|
||||
it 'does not show the default rewrite rule' do
|
||||
node.set['openstack']['dashboard']['http_port'] = 80
|
||||
node.set['openstack']['dashboard']['https_port'] = 443
|
||||
expect(chef_run).not_to render_file(file.name).with_content(default_rewrite_rule)
|
||||
end
|
||||
|
||||
it 'does not show ssl certificate related directives' do
|
||||
[/^\s*SSLEngine on$/,
|
||||
/^\s*SSLCertificateFile/,
|
||||
/^\s*SSLCertificateKeyFile/].each do |ssl_certificate_directive|
|
||||
expect(chef_run).not_to render_file(file.name).with_content(ssl_certificate_directive)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows the ServerAdmin' do
|
||||
node.set['apache']['contact'] = 'apache_contact_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/\s*ServerAdmin apache_contact_value$/)
|
||||
end
|
||||
|
||||
it 'sets the WSGI script alias defaults' do
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(^\s*WSGIScriptAlias / /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi$))
|
||||
end
|
||||
|
||||
it 'sets the WSGI script alias' do
|
||||
node.set['openstack']['dashboard']['wsgi_path'] = 'wsgi_path_value'
|
||||
node.set['openstack']['dashboard']['webroot'] = 'root'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*WSGIScriptAlias root wsgi_path_value$/)
|
||||
end
|
||||
|
||||
it 'sets the WSGI daemon process' do
|
||||
node.set['openstack']['dashboard']['horizon_user'] = 'horizon_user_value'
|
||||
node.set['openstack']['dashboard']['horizon_group'] = 'horizon_group_value'
|
||||
node.set['openstack']['dashboard']['dash_path'] = 'dash_path_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(
|
||||
/^\s*WSGIDaemonProcess dashboard user=horizon_user_value group=horizon_group_value processes=3 threads=10 python-path=dash_path_value$/)
|
||||
end
|
||||
|
||||
it 'has the default DocRoot' do
|
||||
node.set['openstack']['dashboard']['dash_path'] = 'dash_path_value'
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(%r(\s*DocumentRoot dash_path_value/.blackhole/$))
|
||||
end
|
||||
|
||||
it 'has TraceEnable set' do
|
||||
node.set['openstack']['dashboard']['traceenable'] = 'value'
|
||||
expect(chef_run).to render_file(file.name)
|
||||
.with_content(/^ TraceEnable value$/)
|
||||
end
|
||||
|
||||
it 'sets the right Alias path for /static' do
|
||||
node.set['openstack']['dashboard']['static_path'] = 'static_path_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s+Alias \/static static_path_value$/)
|
||||
end
|
||||
|
||||
%w(dash_path static_path).each do |dir_attribute|
|
||||
it "sets the #{dir_attribute} directory directive" do
|
||||
node.set['openstack']['dashboard'][dir_attribute] = "#{dir_attribute}_value"
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*<Directory #{dir_attribute}_value>$/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'log directives' do
|
||||
before do
|
||||
node.set['apache']['log_dir'] = 'log_dir_value'
|
||||
end
|
||||
|
||||
it 'sets de ErrorLog directive' do
|
||||
node.set['openstack']['dashboard']['error_log'] = 'error_log_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*ErrorLog log_dir_value\/error_log_value$/)
|
||||
end
|
||||
|
||||
it 'sets de CustomLog directive' do
|
||||
node.set['openstack']['dashboard']['access_log'] = 'access_log_value'
|
||||
expect(chef_run).to render_file(file.name).with_content(/^\s*CustomLog log_dir_value\/access_log_value combined$/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets wsgi socket prefix if wsgi_socket_prefix attribute is preset' do
|
||||
node.set['openstack']['dashboard']['wsgi_socket_prefix'] = '/var/run/wsgi'
|
||||
expect(chef_run).to render_file(file.name).with_content(%r(^WSGISocketPrefix /var/run/wsgi$))
|
||||
end
|
||||
|
||||
it 'omits wsgi socket prefix if wsgi_socket_prefix attribute is not preset' do
|
||||
node.set['openstack']['dashboard']['wsgi_socket_prefix'] = nil
|
||||
expect(chef_run).not_to render_file(file.name).with_content(/^WSGISocketPrefix $/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'notifies restore-selinux-context' do
|
||||
expect(file).to notify('execute[restore-selinux-context]').to(:run)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'secret_key_path file' do
|
||||
secret_key_path = '/var/lib/openstack-dashboard/secret_key'
|
||||
let(:file) { chef_run.file(secret_key_path) }
|
||||
|
||||
it 'has correct ownership' do
|
||||
expect(file.owner).to eq('horizon')
|
||||
expect(file.group).to eq('horizon')
|
||||
end
|
||||
|
||||
it 'has correct mode' do
|
||||
expect(file.mode).to eq(00600)
|
||||
end
|
||||
|
||||
it 'does not notify apache2 restart' do
|
||||
expect(file).not_to notify('service[apache2]').to(:restart)
|
||||
end
|
||||
|
||||
it 'has configurable path and ownership settings' do
|
||||
node.set['openstack']['dashboard']['secret_key_path'] = 'somerandompath'
|
||||
node.set['openstack']['dashboard']['horizon_user'] = 'somerandomuser'
|
||||
node.set['openstack']['dashboard']['horizon_group'] = 'somerandomgroup'
|
||||
file = chef_run.file('somerandompath')
|
||||
expect(file.owner).to eq('somerandomuser')
|
||||
expect(file.group).to eq('somerandomgroup')
|
||||
end
|
||||
|
||||
describe 'secret_key_content set' do
|
||||
before do
|
||||
node.set['openstack']['dashboard']['secret_key_content'] = 'somerandomcontent'
|
||||
end
|
||||
|
||||
it 'has configurable secret_key_content setting' do
|
||||
expect(chef_run).to render_file(file.name).with_content('somerandomcontent')
|
||||
end
|
||||
|
||||
it 'notifies apache2 restart when secret_key_content set' do
|
||||
expect(file).to notify('service[apache2]').to(:restart)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not delete openstack-dashboard.conf' do
|
||||
file = '/etc/httpd/conf.d/openstack-dashboard.conf'
|
||||
|
||||
expect(chef_run).not_to delete_file(file)
|
||||
end
|
||||
|
||||
it 'removes openstack-dashboard-ubuntu-theme package' do
|
||||
expect(chef_run).to purge_package('openstack-dashboard-ubuntu-theme')
|
||||
end
|
||||
|
||||
it 'calls apache_site to disable 000-default virtualhost' do
|
||||
|
||||
resource = chef_run.find_resource('execute',
|
||||
'a2dissite 000-default').to_hash
|
||||
expect(resource).to include(
|
||||
action: 'run',
|
||||
params: {
|
||||
enable: false,
|
||||
name: '000-default'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'calls apache_site to enable openstack-dashboard virtualhost' do
|
||||
|
||||
resource = chef_run.find_resource('execute',
|
||||
'a2ensite openstack-dashboard').to_hash
|
||||
expect(resource).to include(
|
||||
action: 'run',
|
||||
params: {
|
||||
enable: true,
|
||||
notifies: [:reload, 'service[apache2]', :immediately],
|
||||
name: 'openstack-dashboard'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'notifies apache2 restart' do
|
||||
skip 'TODO: how to test when tied to an LWRP'
|
||||
end
|
||||
|
||||
it 'does not execute restore-selinux-context' do
|
||||
cmd = 'restorecon -Rv /etc/httpd /etc/pki; chcon -R -t httpd_sys_content_t /usr/share/openstack-dashboard || :'
|
||||
|
||||
expect(chef_run).not_to run_execute(cmd)
|
||||
end
|
||||
|
||||
it 'has group write mode on path' do
|
||||
path = chef_run.directory("#{chef_run.node['openstack']['dashboard']['dash_path']}/local")
|
||||
expect(path.mode).to eq(02770)
|
||||
expect(path.group).to eq(chef_run.node['openstack']['dashboard']['horizon_group'])
|
||||
end
|
||||
let(:runner) { ChefSpec::Runner.new(UBUNTU_OPTS) }
|
||||
let(:node) { runner.node }
|
||||
let(:chef_run) do
|
||||
runner.converge(described_recipe)
|
||||
end
|
||||
|
||||
include_context 'non_redhat_stubs'
|
||||
include_context 'dashboard_stubs'
|
||||
|
||||
it 'installs the horizon dashboard' do
|
||||
expect(chef_run).to include_recipe('openstack-dashboard::horizon')
|
||||
end
|
||||
|
||||
it 'by default installs the apache2 webserver' do
|
||||
expect(chef_run).to include_recipe('openstack-dashboard::apache2-server')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue