chef/cookbooks/nova/recipes/config.rb
#
# Cookbook Name:: nova
# Recipe:: config
#
# Copyright 2010, 2011 Opscode, Inc.
# Copyright 2011 Dell, Inc.
# Copyright 2014, SUSE Linux Products 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.
#
keystone_settings = KeystoneHelper.keystone_settings(node, :nova)
profiler_settings = KeystoneHelper.profiler_settings(node, @cookbook_name)
is_controller = node["roles"].include?("nova-controller")
my_ip_net = "admin"
# z/VM compute nodes might need a different "my_ip" setting to be accessible
# from the xCAT management node
if node["roles"].include?("nova-compute-zvm")
my_ip_net = node["nova"]["zvm"]["zvm_xcat_network"]
end
node.set[:nova][:my_ip] =
Chef::Recipe::Barclamp::Inventory.get_network_by_type(node, my_ip_net).address
package "nova-common" do
if %w(rhel suse).include?(node[:platform_family])
package_name "openstack-nova"
end
action :install
end
# Fake service to take control of the WSGI process from apache that
# runs Placement API. We replace the `reload` action, sending
# manually the signal SIGUSR1 to all the process that are part of
# `wsgi:nova-placement-api`
service "nova-placement-api" do
service_name "apache2"
if node[:platform_family] == "suse"
reload_command 'sleep 1 && pkill --signal SIGUSR1 -f "^\(wsgi:nova-placement" && sleep 1'
end
supports reload: true, restart: true, status: true
ignore_failure true
end
# don't expose database connection to the compute clients
if is_controller
db_settings = fetch_database_settings
include_recipe "database::client"
include_recipe "#{db_settings[:backend_name]}::client"
include_recipe "#{db_settings[:backend_name]}::python-client"
database_connection = fetch_database_connection_string(node[:nova][:db])
placement_database_connection = fetch_database_connection_string(node[:nova][:placement_db])
api_database_connection = fetch_database_connection_string(node[:nova][:api_db])
else
database_connection = nil
api_database_connection = nil
end
api = if is_controller
node
else
node_search_with_cache("roles:nova-controller").first
end
# use nova-rootwrap daemon on compute-only nodes
use_rootwrap_daemon = !is_controller
api_ha_enabled = api[:nova][:ha][:enabled]
admin_api_host = CrowbarHelper.get_host_for_admin_url(api, api_ha_enabled)
public_api_host = CrowbarHelper.get_host_for_public_url(api, api[:nova][:ssl][:enabled], api_ha_enabled)
Chef::Log.info("Api server found at #{admin_api_host} #{public_api_host}")
glance_servers = node_search_with_cache("roles:glance-server")
if glance_servers.length > 0
glance_server = glance_servers[0]
glance_server = node if glance_server.name == node.name
glance_server_host = CrowbarHelper.get_host_for_admin_url(glance_server, (glance_server[:glance][:ha][:enabled] rescue false))
glance_server_port = glance_server[:glance][:api][:bind_port]
glance_server_protocol = glance_server[:glance][:api][:protocol]
else
glance_server_host = nil
glance_server_port = nil
glance_server_protocol = nil
end
glance_config = Barclamp::Config.load("openstack", "glance", node[:nova][:glance_instance])
glance_insecure = CrowbarOpenStackHelper.insecure(glance_config) || keystone_settings["insecure"]
Chef::Log.info("Glance server at #{glance_server_host}")
memcached_instance "nova" if is_controller
directory "/etc/nova" do
mode 0755
action :create
end
rbd_enabled = false
ephemeral_rbd_settings = nil
cinder_servers = node_search_with_cache("roles:cinder-controller")
if cinder_servers.length > 0
cinder_server = cinder_servers[0]
use_multipath = cinder_server[:cinder][:use_multipath]
keymgr_fixed_key = cinder_server[:cinder][:keymgr_fixed_key]
if node.roles.include? "nova-compute-kvm"
# make sure cinder volumes are filled with settings from SES data bag
SesHelper.populate_cinder_volumes_with_ses_settings(cinder_server)
cinder_server[:cinder][:volumes].each do |volume|
next unless volume["backend_driver"] == "rbd"
rbd_enabled = true
next unless node[:nova][:use_rbd_ephemeral]
# use first rbd cinder backend for ephemeral storage settings
ephemeral_rbd_settings = volume[:rbd].clone
# override pool with nova section from settings
ses_config = SesHelper.ses_settings
ephemeral_rbd_settings[:pool] = ses_config[:nova][:rbd_store_pool]
break
end
end
else
use_multipath = false
keymgr_fixed_key = ""
end
cinder_config = Barclamp::Config.load("openstack", "cinder", node[:nova][:cinder_instance])
cinder_insecure = CrowbarOpenStackHelper.insecure(cinder_config) || keystone_settings["insecure"]
if rbd_enabled
include_recipe "nova::ceph"
end
neutron_servers = node_search_with_cache("roles:neutron-server")
if neutron_servers.length > 0
neutron_server = neutron_servers[0]
neutron_server = node if neutron_server.name == node.name
neutron_protocol = neutron_server[:neutron][:api][:protocol]
neutron_server_host = CrowbarHelper.get_host_for_admin_url(neutron_server, (neutron_server[:neutron][:ha][:server][:enabled] rescue false))
neutron_server_port = neutron_server[:neutron][:api][:service_port]
neutron_service_user = neutron_server[:neutron][:service_user]
neutron_service_password = neutron_server[:neutron][:service_password]
neutron_dhcp_domain = neutron_server[:neutron][:dns_domain]
neutron_ml2_drivers = neutron_server[:neutron][:ml2_type_drivers]
neutron_has_tunnel = neutron_ml2_drivers.include?("gre") || neutron_ml2_drivers.include?("vxlan")
else
neutron_server_host = nil
neutron_server_port = nil
neutron_service_user = nil
neutron_dhcp_domain = "novalocal"
neutron_service_password = nil
neutron_has_tunnel = false
end
neutron_config = Barclamp::Config.load("openstack", "neutron", node[:nova][:neutron_instance])
neutron_insecure = CrowbarOpenStackHelper.insecure(neutron_config) || keystone_settings["insecure"]
Chef::Log.info("Neutron server at #{neutron_server_host}")
has_itxt = false
oat_server = node
unless node[:nova][:itxt_instance].nil? || node[:nova][:itxt_instance].empty?
env_filter = " AND inteltxt_config_environment:inteltxt-config-#{node[:nova][:itxt_instance]}"
oat_servers = search(:node, "roles:oat-server#{env_filter}") || []
unless oat_servers.empty?
has_itxt = true
oat_server = oat_servers[0]
execute "fill_cert" do
command <<-EOF
echo | openssl s_client -connect "#{oat_server[:hostname]}:8443" -cipher DHE-RSA-AES256-SHA > /etc/nova/oat_certfile.cer || rm -fv /etc/nova/oat_certfile.cer
EOF
not_if { File.exist? "/etc/nova/oat_certfile.cer" }
end
end
end
# only put certificates in nova.conf for controllers; on compute nodes, we
# don't need them and specifying them results in the certificates being queried
# when creating clients for glance
if api[:nova][:ssl][:enabled] && is_controller
api_ssl_certfile = api[:nova][:ssl][:certfile]
api_ssl_keyfile = api[:nova][:ssl][:keyfile]
api_ssl_cafile = api[:nova][:ssl][:ca_certs]
else
api_ssl_certfile = ""
api_ssl_keyfile = ""
api_ssl_cafile = ""
end
# if there's no certificate for novnc, use the ones from nova-api
if api[:nova][:novnc][:ssl][:enabled] && is_controller
if api[:nova][:novnc][:ssl][:certfile].empty?
api_novnc_ssl_certfile = api[:nova][:ssl][:certfile]
api_novnc_ssl_keyfile = api[:nova][:ssl][:keyfile]
else
api_novnc_ssl_certfile = api[:nova][:novnc][:ssl][:certfile]
api_novnc_ssl_keyfile = api[:nova][:novnc][:ssl][:keyfile]
end
else
api_novnc_ssl_certfile = ""
api_novnc_ssl_keyfile = ""
end
# only require certs for nova controller
if (api_ha_enabled || api == node) && \
api[:nova][:ssl][:enabled] && is_controller
ssl_setup "setting up ssl for nova" do
generate_certs api[:nova][:ssl][:generate_certs]
certfile api[:nova][:ssl][:certfile]
keyfile api[:nova][:ssl][:keyfile]
group api[:nova][:group]
fqdn api[:fqdn]
cert_required api[:nova][:ssl][:cert_required]
ca_certs api[:nova][:ssl][:ca_certs]
end
end
if (api_ha_enabled || api == node) && \
api[:nova][:novnc][:ssl][:enabled] && is_controller
# No check if we're using certificate info from nova-api
unless ::File.size?(api_novnc_ssl_certfile) || api[:nova][:novnc][:ssl][:certfile].empty?
message = "Certificate \"#{api_novnc_ssl_certfile}\" is not present or empty."
Chef::Log.fatal(message)
raise message
end
end
admin_address = Chef::Recipe::Barclamp::Inventory.get_network_by_type(node, "admin").address
metadata_bind_address = admin_address
if node[:nova][:ha][:enabled]
bind_host = admin_address
bind_port_api = node[:nova][:ha][:ports][:api]
bind_port_api_ec2 = node[:nova][:ha][:ports][:api_ec2]
bind_port_metadata = node[:nova][:ha][:ports][:metadata]
bind_port_objectstore = node[:nova][:ha][:ports][:objectstore]
bind_port_novncproxy = node[:nova][:ha][:ports][:novncproxy]
bind_port_serialproxy = node[:nova][:ha][:ports][:serialproxy]
else
bind_host = "0.0.0.0"
bind_port_api = node[:nova][:ports][:api]
bind_port_api_ec2 = node[:nova][:ports][:api_ec2]
bind_port_metadata = node[:nova][:ports][:metadata]
bind_port_objectstore = node[:nova][:ports][:objectstore]
bind_port_novncproxy = node[:nova][:ports][:novncproxy]
bind_port_serialproxy = node[:nova][:ports][:serialproxy]
end
ironic_servers = node_search_with_cache("roles:ironic-server") || []
if ironic_servers.any? && (node["roles"] & ["nova-compute-ironic", "nova-controller"]).any?
use_baremetal_filters = true
track_instance_changes = false
ironic_node = ironic_servers.first
ironic_settings = {}
ironic_settings[:keystone_version] = "v3"
ironic_settings[:api_protocol] = ironic_node[:ironic][:api][:protocol]
ironic_settings[:api_port] = ironic_node[:ironic][:api][:port]
ironic_settings[:api_host] = CrowbarHelper.get_host_for_admin_url(
ironic_node,
ironic_settings[:api_protocol] == "https"
)
ironic_settings[:service_user] = ironic_node[:ironic][:service_user]
ironic_settings[:service_password] = ironic_node[:ironic][:service_password]
reserved_host_memory = 0
else
use_baremetal_filters = false
track_instance_changes = true
ironic_settings = nil
reserved_host_memory = node[:nova][:scheduler][:reserved_host_memory_mb]
end
vendordata_jsonfile = "/etc/nova/suse-vendor-data.json"
template vendordata_jsonfile do
source "suse-vendor-data.json.erb"
user "root"
group node[:nova][:group]
mode 0640
variables(
vendor_data: node[:nova][:metadata][:vendordata][:json]
)
end
# Allow to use some specific NICs for live migration
live_migration_inbound_fqdn = if node[:nova][:migration][:network] == "admin"
node[:fqdn]
else
"#{node[:nova][:migration][:network]}.#{node[:fqdn]}"
end
# Select libvirt compute flags for this particular compute node
# type. Differentiate between qemu and kvm as for aarch64 that
# makes a difference.
cpu_mode = ""
cpu_model = ""
rng_device = nil
if node.roles.include? "nova-compute-kvm"
compute_flags = node[:nova][:compute]["kvm-#{node[:kernel][:machine]}"]
elsif node.roles.include? "nova-compute-qemu"
compute_flags = node[:nova][:compute]["qemu-#{node[:kernel][:machine]}"]
end
if compute_flags
cpu_model = compute_flags["cpu_model"]
cpu_mode = compute_flags["cpu_mode"]
end
if File.exist?("/sys/devices/virtual/misc/hw_random/rng_current") &&
!File.read("/sys/devices/virtual/misc/hw_random/rng_current").include?("none")
# Unfortunately that file isn't readable by non-root so we can not set it
# rng_device = "/dev/hwrng"
else
rng_device = "/dev/random"
end
# lock path prevents race conditions for cinder-volume and nova-compute on same
# node. Keep code in sync between cinder and nova recipes. For reference check
# http://docs.openstack.org/releasenotes/nova/newton.html
need_shared_lock_path = node.roles.include?("cinder-volume") && \
node.roles.any? { |role| /^nova-compute-/ =~ role }
if need_shared_lock_path
group "openstack" do
members "nova"
append true
end
include_recipe "crowbar-openstack::common"
end
template node[:nova][:placement_config_file] do
source "nova-placement.conf.erb"
user "root"
group node[:nova][:group]
mode 0640
variables(
keystone_settings: keystone_settings,
profiler_settings: profiler_settings,
placement_database_connection: placement_database_connection,
placement_service_user: node["nova"]["placement_service_user"],
placement_service_password: node["nova"]["placement_service_password"],
placement_service_insecure: node[:nova][:ssl][:insecure]
)
notifies :reload, "service[nova-placement-api]"
end
template node[:nova][:config_file] do
source "nova.conf.erb"
user "root"
group node[:nova][:group]
mode 0640
variables(
cpu_mode: cpu_mode,
cpu_model: cpu_model,
bind_host: bind_host,
rng_device: rng_device,
bind_port_api: bind_port_api,
bind_port_api_ec2: bind_port_api_ec2,
bind_port_metadata: bind_port_metadata,
bind_port_objectstore: bind_port_objectstore,
bind_port_novncproxy: bind_port_novncproxy,
bind_port_serialproxy: bind_port_serialproxy,
database_connection: database_connection,
api_database_connection: api_database_connection,
rabbit_settings: fetch_rabbitmq_settings,
libvirt_type: node[:nova][:libvirt_type],
ec2_host: admin_api_host,
ec2_dmz_host: public_api_host,
libvirt_migration: node[:nova]["use_migration"],
live_migration_inbound_fqdn: live_migration_inbound_fqdn,
shared_instances: node[:nova]["use_shared_instance_storage"],
force_config_drive: node[:nova]["force_config_drive"],
glance_server_protocol: glance_server_protocol,
glance_server_host: glance_server_host,
glance_server_port: glance_server_port,
glance_server_insecure: glance_insecure,
need_shared_lock_path: need_shared_lock_path,
metadata_bind_address: metadata_bind_address,
vnc_enabled: node[:nova][:use_novnc],
serial_enabled: node[:nova][:use_serial],
vendordata_jsonfile: vendordata_jsonfile,
vncproxy_public_host: public_api_host,
vncproxy_ssl_enabled: api[:nova][:novnc][:ssl][:enabled],
vncproxy_cert_file: api_novnc_ssl_certfile,
vncproxy_key_file: api_novnc_ssl_keyfile,
serialproxy_public_host: public_api_host,
memcached_servers: MemcachedHelper.get_memcached_servers(node,
CrowbarPacemakerHelper.cluster_nodes(node, "nova-controller")),
neutron_protocol: neutron_protocol,
neutron_server_host: neutron_server_host,
neutron_server_port: neutron_server_port,
neutron_insecure: neutron_insecure,
neutron_service_user: neutron_service_user,
neutron_service_password: neutron_service_password,
neutron_dhcp_domain: neutron_dhcp_domain,
neutron_has_tunnel: neutron_has_tunnel,
keystone_settings: keystone_settings,
profiler_settings: profiler_settings,
cinder_insecure: cinder_insecure,
use_multipath: use_multipath,
keymgr_fixed_key: keymgr_fixed_key,
ssl_enabled: api[:nova][:ssl][:enabled],
ssl_cert_file: api_ssl_certfile,
ssl_key_file: api_ssl_keyfile,
ssl_cert_required: api[:nova][:ssl][:cert_required],
ssl_ca_file: api_ssl_cafile,
use_rootwrap_daemon: use_rootwrap_daemon,
oat_appraiser_host: oat_server[:hostname],
oat_appraiser_port: "8443",
has_itxt: has_itxt,
enabled_filters: node[:nova][:scheduler][:enabled_filters],
reserved_host_memory: reserved_host_memory,
use_baremetal_filters: use_baremetal_filters,
track_instance_changes: track_instance_changes,
ironic_settings: ironic_settings,
ephemeral_rbd_settings: ephemeral_rbd_settings,
default_log_levels: node[:nova][:default_log_levels]
)
end
# dependency for crowbar-nova-set-availability-zone
package "python-novaclient"
cookbook_file "crowbar-nova-set-availability-zone" do
source "crowbar-nova-set-availability-zone"
path "/usr/bin/crowbar-nova-set-availability-zone"
mode "0755"
end