chef/cookbooks/swift/recipes/proxy.rb
#
# Copyright 2011, Dell
#
# 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.
#
# Author: andi abes
#
ses_config = SesHelper.ses_settings
include_recipe "utils"
# Note: we always want to setup rsync, even if we do not do anything else; this
# will allow the ring-compute node to push the rings.
include_recipe "swift::rsync"
dirty = false
if node.roles.include?("swift-storage") && node[:swift][:devs].nil?
# If we're a storage node and have no device yet, then it simply means that we
# haven't looked for devices yet, which also means that we won't have rings at
# this point in time, so swift-proxy will fail.
Chef::Log.info("Not setting up swift-proxy daemon; this chef run is only used to find disks on storage nodes.")
return
end
if node.roles.include?("swift-ring-compute") && !::File.exist?("/etc/swift/object.ring.gz")
# Similarly to above; the difference is that we will have the rings in the
# execute phase, but we do not want to be the only proxy node with the rings
# (which would be the case, since we're in the ring-compute pass of swift
# orchestration): we want all nodes to start swift-proxy at the same time.
Chef::Log.info("Not setting up swift-proxy daemon; this chef run is only used to compute the rings.")
return
end
if node.roles.include?("swift-storage") && !node["swift"]["storage_init_done"]
# We're a storage node, and we have devices. But have we setup the storage
# daemons? If not, then we're not in the chef run for swift-proxy yet.
Chef::Log.info("Not setting up swift-proxy daemon; this chef run is only used to setup swift-{account,container,object}.")
return
end
ha_enabled = node[:swift][:ha][:enabled]
bind_host, bind_port = SwiftHelper.get_bind_host_port(node)
admin_host = CrowbarHelper.get_host_for_admin_url(node, ha_enabled)
public_host = CrowbarHelper.get_host_for_public_url(node, node[:swift][:ssl][:enabled], ha_enabled)
swift_protocol = node[:swift][:ssl][:enabled] ? "https" : "http"
###
# bucket to collect all the config items that end up in the proxy config template
proxy_config = {}
proxy_config[:bind_host] = bind_host
proxy_config[:bind_port] = bind_port
proxy_config[:auth_method] = node[:swift][:auth_method]
proxy_config[:user] = node[:swift][:user]
proxy_config[:debug] = node[:swift][:debug]
proxy_config[:admin_host] = admin_host
proxy_config[:proxy_port] = node[:swift][:ports][:proxy]
### middleware items
proxy_config[:clock_accuracy] = node[:swift][:middlewares][:ratelimit][:clock_accuracy]
proxy_config[:max_sleep_time_seconds] = node[:swift][:middlewares][:ratelimit][:max_sleep_time_seconds]
proxy_config[:log_sleep_time_seconds] = node[:swift][:middlewares][:ratelimit][:log_sleep_time_seconds]
proxy_config[:rate_buffer_seconds] = node[:swift][:middlewares][:ratelimit][:rate_buffer_seconds]
proxy_config[:account_ratelimit] = node[:swift][:middlewares][:ratelimit][:account_ratelimit]
proxy_config[:account_whitelist] = node[:swift][:middlewares][:ratelimit][:account_whitelist]
proxy_config[:account_blacklist] = node[:swift][:middlewares][:ratelimit][:account_blacklist]
proxy_config[:container_ratelimit_size] = node[:swift][:middlewares][:ratelimit][:container_ratelimit_size]
proxy_config[:lookup_depth] = node[:swift][:middlewares][:cname_lookup][:lookup_depth]
proxy_config[:storage_domain] = node[:swift][:middlewares][:cname_lookup][:storage_domain]
proxy_config[:storage_domain_remap] = node[:swift][:middlewares][:domain_remap][:storage_domain]
proxy_config[:path_root] = node[:swift][:middlewares][:domain_remap][:path_root]
proxy_config[:protocol] = swift_protocol
proxy_config[:ssl_enabled] = node[:swift][:ssl][:enabled]
proxy_config[:ssl_certfile] = node[:swift][:ssl][:certfile]
proxy_config[:ssl_keyfile] = node[:swift][:ssl][:keyfile]
proxy_config[:rabbit_settings] = fetch_rabbitmq_settings
proxy_config[:max_containers_per_extraction] = node[:swift][:middlewares][:bulk][:max_containers_per_extraction]
proxy_config[:max_failed_extractions] = node[:swift][:middlewares][:bulk][:max_failed_extractions]
proxy_config[:max_deletes_per_request] = node[:swift][:middlewares][:bulk][:max_deletes_per_request]
proxy_config[:max_failed_deletes] = node[:swift][:middlewares][:bulk][:max_failed_deletes]
proxy_config[:yield_frequency] = node[:swift][:middlewares][:bulk][:yield_frequency]
cross_domain_policy = node[:swift][:middlewares][:crossdomain][:cross_domain_policy]
# make sure that cross_domain_policy value fits the required format
# see http://docs.openstack.org/developer/swift/crossdomain.html
cross_domain_policy_l = cross_domain_policy.split("\n").each_with_index.map do |line,index|
line = "\t" + line unless index == 0
line
end
proxy_config[:cross_domain_policy] = cross_domain_policy_l.join("\n")
if node[:platform_family] == "rhel"
pkg_list = ["curl", "python-dns"]
else
pkg_list = ["curl", "python-dnspython"]
end
pkg_list.each do |pkg|
package pkg
end
if %w(rhel suse).include?(node[:platform_family])
package "openstack-swift-proxy"
else
package "swift-proxy"
end
if node[:swift][:middlewares][:s3][:enabled]
if %w(rhel suse).include?(node[:platform_family])
package "python-swift3"
else
package "swift-plugin-s3"
end
end
# enable ceilometer middleware if ceilometer is configured
ceilometermiddleware_enabled = node.roles.include? "ceilometer-swift-proxy-middleware"
# unless rabbitmq is secured (see lp#1673738) or is using durable queues
ceilometermiddleware_should_be_disabled = proxy_config[:rabbit_settings][:use_ssl] ||
proxy_config[:rabbit_settings][:durable_queues]
if ceilometermiddleware_enabled && ceilometermiddleware_should_be_disabled
Chef::Log.warn("Disabling ceilometer swift-proxy middleware")
end
ceilometer_swift_enabled = {
"enabled" => ceilometermiddleware_enabled && !ceilometermiddleware_should_be_disabled
}
node.set[:swift] ||= {}
node.set[:swift][:middlewares] ||= {}
if node[:swift][:middlewares]["ceilometer"] != ceilometer_swift_enabled
node.set[:swift][:middlewares]["ceilometer"] = ceilometer_swift_enabled
dirty = true
end
if node[:swift][:middlewares]["ceilometer"]["enabled"]
package "python-ceilometermiddleware"
end
case proxy_config[:auth_method]
when "swauth"
package "python-swauth"
proxy_config[:admin_key] =node[:swift][:cluster_admin_pw]
when "keystone"
keystone_settings = KeystoneHelper.keystone_settings(node, @cookbook_name)
package "python-keystonemiddleware"
package "python-keystoneclient"
proxy_config[:keystone_settings] = keystone_settings
proxy_config[:reseller_prefix] = node[:swift][:reseller_prefix]
proxy_config[:keystone_delay_auth_decision] = node["swift"]["keystone_delay_auth_decision"]
# Because syncmarks are not reset when applying Swift proposal, nodes
# can be out of sync beyond normal syncmark timeout. This 'sync' syncmark
# should line them up and correct any time offsets.
if ha_enabled
crowbar_pacemaker_sync_mark "sync-swift_before_register" do
timeout 300
end
end
crowbar_pacemaker_sync_mark "wait-swift_register" if ha_enabled
register_auth_hash = { user: keystone_settings["admin_user"],
password: keystone_settings["admin_password"],
project: keystone_settings["admin_project"] }
keystone_register "swift proxy 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
# ResellerAdmin is used by swift (see reseller_admin_role option)
role = "ResellerAdmin"
keystone_register "add #{role} role for swift" 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 "register swift 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 swift 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 "register swift service" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
auth register_auth_hash
port keystone_settings["admin_port"]
service_name "swift"
service_type "object-store"
service_description "Openstack Swift Object Store Service"
action :add_service
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
# register swift-proxy endpoints only if no SES based RadosGW is being
# registered in keystone/recipes/ses.rb
if ses_config.nil? || ses_config.fetch("radosgw_urls", []).empty?
keystone_register "register swift-proxy endpoint" do
protocol keystone_settings["protocol"]
insecure keystone_settings["insecure"]
host keystone_settings["internal_url_host"]
auth register_auth_hash
port keystone_settings["admin_port"]
endpoint_service "swift"
endpoint_region keystone_settings["endpoint_region"]
endpoint_publicURL "#{swift_protocol}://#{public_host}:"\
"#{node[:swift][:ports][:proxy]}/v1/"\
"#{node[:swift][:reseller_prefix]}$(project_id)s"
endpoint_adminURL "#{swift_protocol}://#{admin_host}:"\
"#{node[:swift][:ports][:proxy]}/v1/"
endpoint_internalURL "#{swift_protocol}://#{admin_host}:"\
"#{node[:swift][:ports][:proxy]}/v1/"\
"#{node[:swift][:reseller_prefix]}$(project_id)s"
action :add_endpoint
only_if { !ha_enabled || CrowbarPacemakerHelper.is_cluster_founder?(node) }
end
end
crowbar_pacemaker_sync_mark "create-swift_register" if ha_enabled
when "tempauth"
## uses defaults...
end
if node[:swift][:ssl][:enabled]
ssl_setup "setting up ssl for swift" do
generate_certs node[:swift][:ssl][:generate_certs]
certfile node[:swift][:ssl][:certfile]
keyfile node[:swift][:ssl][:keyfile]
group node[:swift][:group]
fqdn node[:fqdn]
end
end
## install a default memcached instance.
## default configuration is taken from: node[:memcached] / [:memory], [:port] and [:user]
memcached_instance "swift-proxy"
proxy_config[:memcached_ips] =
MemcachedHelper.get_memcached_servers(node, node_search_with_cache("roles:swift-proxy"))
## Create the proxy server configuraiton file
template node[:swift][:proxy_config_file] do
source "proxy-server.conf.erb"
mode "0640"
owner "root"
group node[:swift][:group]
variables proxy_config
end
## make sure to fetch ring files from the ring compute node
compute_nodes = node_search_with_cache("roles:swift-ring-compute")
if (!compute_nodes.nil? and compute_nodes.length > 0 and node[:fqdn]!=compute_nodes[0][:fqdn] )
compute_node_addr = Swift::Evaluator.get_ip_by_type(compute_nodes[0],:storage_ip_expr)
log("ring compute found on: #{compute_nodes[0][:fqdn]} using: #{compute_node_addr}") { level :debug }
%w{container account object}.each { |ring|
execute "pull #{ring} ring" do
user node[:swift][:user]
group node[:swift][:group]
command "rsync #{node[:swift][:user]}@#{compute_node_addr}::ring/#{ring}.ring.gz ."
cwd "/etc/swift"
ignore_failure true
end
}
end
ruby_block "Check if ring is present" do
block do
Chef::Log.info("Not setting up swift-proxy daemon; ring-compute node hasn't pushed the rings yet.")
end
not_if { ::File.exist? "/etc/swift/object.ring.gz" }
end
if node[:swift][:frontend]=="native"
service "swift-proxy" do
service_name node[:swift][:proxy][:service_name]
if %w(rhel suse).include?(node[:platform_family])
supports status: true, restart: true
else
restart_command "stop swift-proxy ; start swift-proxy"
end
action [:enable, :start]
subscribes :restart, resources(template: node[:swift][:config_file]), :immediately
subscribes :restart, resources(template: node[:swift][:proxy_config_file]), :immediately
# Do not even try to start the daemon if we don't have the ring yet
only_if { ::File.exist? "/etc/swift/object.ring.gz" }
end
utils_systemd_service_restart "swift-proxy" do
action :enable
only_if { ::File.exist? "/etc/swift/object.ring.gz" }
end
elsif node[:swift][:frontend]=="uwsgi"
service "swift-proxy" do
service_name node[:swift][:proxy][:service_name]
supports status: true, restart: true
action [:disable, :stop]
end
directory "/usr/lib/cgi-bin/swift/" do
owner "root"
group "root"
mode 0755
action :create
recursive true
end
template "/usr/lib/cgi-bin/swift/proxy.py" do
source "swift-uwsgi-service.py.erb"
mode 0755
variables(
service: "proxy"
)
end
if node[:swift][:ssl][:enabled]
uwsgi_instances = {
https: "#{bind_host}:#{bind_port},#{node[:swift][:ssl][:certfile]},#{node[:swift][:ssl][:keyfile]}"
}
else
uwsgi_instances = {
http: "#{bind_host}:#{bind_port}"
}
end
uwsgi "swift-proxy" do
options({
:chdir => "/usr/lib/cgi-bin/swift/",
:callable => :application,
:module => :proxy,
:protocol => swift_protocol,
:user => :swift,
:vacuum => true,
:"no-orphans" => true,
:"reload-on-rss" => 192,
:"reload-on-as" => 256,
:"max-requests" => 2000,
:"cpu-affinity" => 1,
:"reload-mercy" => 8,
:processes => 4,
:"buffer-size" => 65535,
:harakiri => 60,
:log => "/var/log/swift-proxy-uwsgi.log"
})
instances (uwsgi_instances)
service_name "swift-proxy-uwsgi"
end
service "swift-proxy-uwsgi" do
supports status: true, restart: true, start: true
action :start
subscribes :restart, "template[/usr/lib/cgi-bin/swift/proxy.py]"
# Do not even try to start the daemon if we don't have the ring yet
only_if { ::File.exist? "/etc/swift/object.ring.gz" }
end
end
if node[:platform_family] == "debian"
bash "restart swift proxy things" do
code <<-EOH
EOH
action :nothing
subscribes :run, resources(template: node[:swift][:proxy_config_file])
if node[:swift][:frontend]=="native"
notifies :restart, resources(service: "swift-proxy")
end
end
end
if ha_enabled
log "HA support for swift is enabled"
include_recipe "swift::proxy_ha"
else
log "HA support for swift is disabled"
end
unless node["swift"]["proxy_init_done"]
node.set["swift"]["proxy_init_done"] = true
dirty = true
end
node.save if dirty