chef/cookbooks/heat/recipes/server.rb
# Copyright 2016 SUSE, Inc.
#
# 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.
#
ha_enabled = node[:heat][:ha][:enabled]
db_settings = fetch_database_settings
include_recipe "database::client"
include_recipe "#{db_settings[:backend_name]}::client"
include_recipe "#{db_settings[:backend_name]}::python-client"
crowbar_pacemaker_sync_mark "wait-heat_database" if ha_enabled
# Create the Heat Database
database "create #{node[:heat][:db][:database]} database" do
connection db_settings[:connection]
database_name node[:heat][:db][:database]
provider db_settings[:provider]
action :create
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
database_user "create heat database user" do
host "%"
connection db_settings[:connection]
username node[:heat][:db][:user]
password node[:heat][:db][:password]
provider db_settings[:user_provider]
action :create
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
database_user "grant database access for heat database user" do
connection db_settings[:connection]
username node[:heat][:db][:user]
password node[:heat][:db][:password]
database_name node[:heat][:db][:database]
host "%"
privileges db_settings[:privs]
provider db_settings[:user_provider]
require_ssl db_settings[:connection][:ssl][:enabled]
action :grant
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
crowbar_pacemaker_sync_mark "create-heat_database" if ha_enabled
node[:heat][:platform][:packages].each do |p|
package p
end
node[:heat][:platform][:plugin_packages].each do |p|
package p
end
# install Cisco GBP plugin if needed
neutron_server = search(:node, "roles:neutron-server").first || []
unless neutron_server.empty?
if neutron_server[:neutron][:ml2_mechanism_drivers].include?("apic_gbp")
# Install GBP plugin if Cisco APIC driver is set to apic_gbp
node[:heat][:platform][:gbp_plugin_packages].each do |p|
package p
end
end
end
directory "/var/cache/heat" do
owner node[:heat][:user]
group node[:heat][:group]
mode 00750
action :create
end
directory "/etc/heat/environment.d" do
owner "root"
group "root"
mode 00755
action :create
end
if node[:heat][:api][:protocol] == "https"
ssl_setup "setting up ssl for heat" do
generate_certs node[:heat][:ssl][:generate_certs]
certfile node[:heat][:ssl][:certfile]
keyfile node[:heat][:ssl][:keyfile]
group node[:heat][:group]
fqdn node[:fqdn]
cert_required node[:heat][:ssl][:cert_required]
ca_certs node[:heat][:ssl][:ca_certs]
end
end
memcached_instance("heat-server")
keystone_settings = KeystoneHelper.keystone_settings(node, @cookbook_name)
bind_host, api_port, cfn_port = HeatHelper.get_bind_host_port(node)
my_admin_host = CrowbarHelper.get_host_for_admin_url(node, ha_enabled)
my_public_host = CrowbarHelper.get_host_for_public_url(node, node[:heat][:api][:protocol] == "https", ha_enabled)
db_connection = fetch_database_connection_string(node[:heat][:db])
crowbar_pacemaker_sync_mark "wait-heat_register" do
timeout 90
only_if { ha_enabled }
end
register_auth_hash = { user: keystone_settings["admin_user"],
password: keystone_settings["admin_password"],
project: keystone_settings["admin_project"] }
keystone_register "heat wakeup keystone" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
action :wakeup
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
keystone_register "register heat user" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
user_name keystone_settings["service_user"]
user_password keystone_settings["service_password"]
project_name keystone_settings["service_tenant"]
action :add_user
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
keystone_register "give heat user access" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
user_name keystone_settings["service_user"]
project_name keystone_settings["service_tenant"]
role_name "admin"
action :add_access
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
keystone_register "add heat stack user role" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
role_name "heat_stack_user"
action :add_role
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
node[:heat][:trusts_delegated_roles].each do |role|
keystone_register "Create stack owner role #{role}" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
role_name role
action :add_role
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
keystone_register "give admin access to stack owner role #{role}" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
user_name keystone_settings["admin_user"]
project_name keystone_settings["default_tenant"]
role_name role
action :add_access
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
end
package "python-openstackclient" do
action :install
end
stack_user_domain_name = "heat"
insecure = keystone_settings["insecure"] ? "--insecure" : ""
bash "register heat domain" do
user "root"
code <<-EOF
# Find domain ID
HEAT_DOMAIN_ID=$(openstack #{insecure} \
domain show \
-f value -c id \
#{stack_user_domain_name})
if [ -z "$HEAT_DOMAIN_ID" ]; then
HEAT_DOMAIN_ID=$(openstack #{insecure} \
domain create \
-f value -c id \
--description "Owns users and projects created by heat" \
#{stack_user_domain_name})
fi
[ -n "$HEAT_DOMAIN_ID" ] || exit 1
# Find user ID
STACK_DOMAIN_ADMIN_ID=$(openstack #{insecure} \
user show \
-f value -c id \
--domain $HEAT_DOMAIN_ID \
#{node[:heat][:stack_domain_admin]})
# Update heat admin user if exists
if [ -n "$STACK_DOMAIN_ADMIN_ID" ]; then
openstack #{insecure} \
user set \
--domain $HEAT_DOMAIN_ID \
--password #{node[:heat][:stack_domain_admin_password]} \
--description "Manages users and projects created by heat" \
$STACK_DOMAIN_ADMIN_ID
else
STACK_DOMAIN_ADMIN_ID=$(openstack #{insecure} \
user create \
-f value -c id \
--domain $HEAT_DOMAIN_ID \
--password #{node[:heat][:stack_domain_admin_password]} \
--description "Manages users and projects created by heat" \
#{node[:heat][:stack_domain_admin]})
fi
[ -n "$STACK_DOMAIN_ADMIN_ID" ] || exit 1
# Make user an admin
openstack #{insecure} \
role add \
--domain $HEAT_DOMAIN_ID \
--user $STACK_DOMAIN_ADMIN_ID \
admin
EOF
environment ({
"OS_USERNAME" => keystone_settings["admin_user"],
"OS_PASSWORD" => keystone_settings["admin_password"],
"OS_TENANT_NAME" => keystone_settings["admin_tenant"],
"OS_AUTH_URL" => "#{keystone_settings['protocol']}://#{keystone_settings['internal_url_host']}:#{keystone_settings['service_port']}/v3",
"OS_REGION_NAME" => keystone_settings["endpoint_region"],
"OS_IDENTITY_API_VERSION" => "3"
})
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
# Create Heat CloudFormation service
keystone_register "register Heat CloudFormation Service" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
service_name "heat-cfn"
service_type "cloudformation"
service_description "Heat CloudFormation Service"
action :add_service
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
keystone_register "register heat Cfn endpoint" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
endpoint_service "heat-cfn"
endpoint_region keystone_settings["endpoint_region"]
endpoint_publicURL "#{node[:heat][:api][:protocol]}://#{my_public_host}:#{node[:heat][:api][:cfn_port]}/v1"
endpoint_adminURL "#{node[:heat][:api][:protocol]}://#{my_admin_host}:#{node[:heat][:api][:cfn_port]}/v1"
endpoint_internalURL "#{node[:heat][:api][:protocol]}://#{my_admin_host}:#{node[:heat][:api][:cfn_port]}/v1"
action :add_endpoint
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
# Create Heat service
keystone_register "register Heat Service" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
service_name "heat"
service_type "orchestration"
service_description "Heat Service"
action :add_service
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
keystone_register "register heat endpoint" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
port keystone_settings["admin_port"]
auth register_auth_hash
endpoint_service "heat"
endpoint_region keystone_settings["endpoint_region"]
endpoint_publicURL "#{node[:heat][:api][:protocol]}://"\
"#{my_public_host}:"\
"#{node[:heat][:api][:port]}/v1/$(project_id)s"
endpoint_adminURL "#{node[:heat][:api][:protocol]}://"\
"#{my_admin_host}:"\
"#{node[:heat][:api][:port]}/v1/$(project_id)s"
endpoint_internalURL "#{node[:heat][:api][:protocol]}://"\
"#{my_admin_host}:"\
"#{node[:heat][:api][:port]}/v1/$(project_id)s"
action :add_endpoint
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
crowbar_pacemaker_sync_mark "create-heat_register" if ha_enabled
ruby_block "get stack user domain" do
block do
url = "#{keystone_settings["protocol"]}://#{keystone_settings["internal_url_host"]}"
url << ":#{keystone_settings["service_port"]}/v3"
env = "OS_USERNAME='#{keystone_settings["admin_user"]}' "
env << "OS_PASSWORD='#{keystone_settings["admin_password"]}' "
env << "OS_PROJECT_NAME='#{keystone_settings["admin_tenant"]}' "
env << "OS_AUTH_URL='#{url}' "
env << "OS_REGION_NAME='#{keystone_settings["endpoint_region"]}' "
env << "OS_IDENTITY_API_VERSION=3"
stack_user_domain_id = `#{env} openstack #{insecure} \
domain show -f value -c id #{stack_user_domain_name}`
raise "Could not obtain the stack user domain id" if stack_user_domain_id.empty?
node[:heat][:stack_user_domain_id] = stack_user_domain_id.strip
end
end
template "/etc/heat/heat.conf.d/100-heat.conf" do
source "heat.conf.erb"
owner "root"
group node[:heat][:group]
mode "0640"
variables(
lazy {
{
debug: node[:heat][:debug],
rabbit_settings: fetch_rabbitmq_settings,
keystone_settings: keystone_settings,
memcached_servers: MemcachedHelper.get_memcached_servers(node,
CrowbarPacemakerHelper.cluster_nodes(node, "heat-server")),
database_connection: db_connection,
bind_host: bind_host,
api_port: api_port,
cfn_port: cfn_port,
auth_encryption_key: node[:heat][:auth_encryption_key][0, 32],
heat_metadata_server_url: "#{node[:heat][:api][:protocol]}://#{my_public_host}:#{node[:heat][:api][:cfn_port]}",
heat_waitcondition_server_url: "#{node[:heat][:api][:protocol]}://#{my_public_host}:#{node[:heat][:api][:cfn_port]}/v1/waitcondition",
stack_user_domain: node[:heat][:stack_user_domain_id],
stack_domain_admin: node[:heat]["stack_domain_admin"],
stack_domain_admin_password: node[:heat]["stack_domain_admin_password"],
trusts_delegated_roles: node[:heat][:trusts_delegated_roles],
insecure: keystone_settings["insecure"],
heat_ssl: node[:heat][:ssl]
}
}
)
end
crowbar_pacemaker_sync_mark "wait-heat_db_sync" if ha_enabled
execute "heat-manage db_sync" do
user node[:heat][:user]
group node[:heat][:group]
command "heat-manage db_sync"
# We only do the sync the first time, and only if we're not doing HA or if we
# are the founder of the HA cluster (so that it's really only done once).
only_if {
!node[:heat][:db_synced] && (!ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node))
}
end
# We want to keep a note that we've done db_sync, so we don't do it again.
# If we were doing that outside a ruby_block, we would add the note in the
# compile phase, before the actual db_sync is done (which is wrong, since it
# could possibly not be reached in case of errors).
ruby_block "mark node for heat db_sync" do
block do
node.set[:heat][:db_synced] = true
node.save
end
action :nothing
subscribes :create, "execute[heat-manage db_sync]", :immediately
end
crowbar_pacemaker_sync_mark "create-heat_db_sync" if ha_enabled
service "heat-engine" do
service_name node[:heat][:engine][:service_name]
supports status: true, restart: true
action [:enable, :start]
subscribes :restart, resources("template[/etc/heat/heat.conf.d/100-heat.conf]")
end
utils_systemd_service_restart "heat-engine" do
action :enable
end
template "/etc/heat/loadbalancer.template" do
source "loadbalancer.template.erb"
owner "root"
group node[:heat][:group]
mode "0640"
notifies :restart, "service[heat-engine]", :delayed
only_if { node[:platform_family] == "suse" }
end
service "heat-api" do
service_name node[:heat][:api][:service_name]
supports status: true, restart: true
action [:enable, :start]
subscribes :restart, resources("template[/etc/heat/heat.conf.d/100-heat.conf]")
end
utils_systemd_service_restart "heat-api" do
action :enable
end
service "heat-api-cfn" do
service_name node[:heat][:api_cfn][:service_name]
supports status: true, restart: true
action [:enable, :start]
subscribes :restart, resources("template[/etc/heat/heat.conf.d/100-heat.conf]")
end
utils_systemd_service_restart "heat-api-cfn" do
action :enable
end
if ha_enabled
log "HA support for heat is enabled"
include_recipe "heat::ha"
else
log "HA support for heat is disabled"
end