From dc339a859d377f040858f452ef7b824d226555fe Mon Sep 17 00:00:00 2001 From: Jens Rosenboom Date: Tue, 21 Feb 2017 16:53:04 +0100 Subject: [PATCH] Add recipe to deploy Compute service placement-api The placement-api has been added by nova for the Newton cycle, it has become mandatory for Ocata. It is deployed as a wsgi app similar to what we have for keystone and gnocchi already. Change-Id: I1d1f1cc7046cb30a91894a0c884bc861d7f3dd95 --- .rubocop_todo.yml | 15 ++++- attributes/default.rb | 22 ++++++- attributes/nova_conf.rb | 9 ++- recipes/api-os-compute.rb | 6 -- recipes/identity_registration.rb | 58 ++++++++++++++----- recipes/nova-common.rb | 7 +++ recipes/placement_api.rb | 71 +++++++++++++++++++++++ spec/api-os-compute_spec.rb | 8 --- spec/identity_registration_spec.rb | 74 +++++++++++++++++++----- spec/nova-common_spec.rb | 17 ++++++ spec/placement_api_spec.rb | 34 +++++++++++ spec/spec_helper.rb | 4 ++ templates/default/wsgi-template.conf.erb | 41 +++++++++++++ 13 files changed, 317 insertions(+), 49 deletions(-) create mode 100644 recipes/placement_api.rb create mode 100644 spec/placement_api_spec.rb create mode 100644 templates/default/wsgi-template.conf.erb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 7719713c..c16eaaf4 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2017-02-23 16:58:25 +0100 using RuboCop version 0.39.0. +# on 2017-03-06 14:33:48 +0000 using RuboCop version 0.39.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -15,7 +15,7 @@ Metrics/AbcSize: Metrics/MethodLength: Max: 19 -# Offense count: 7 +# Offense count: 8 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: nested, compact Style/ClassAndModuleChildren: @@ -27,8 +27,9 @@ Style/ClassAndModuleChildren: - 'recipes/libvirt_rbd.rb' - 'recipes/nova-common.rb' - 'recipes/nova-setup.rb' + - 'recipes/placement_api.rb' -# Offense count: 6 +# Offense count: 7 Style/Documentation: Exclude: - 'spec/**/*' @@ -39,6 +40,7 @@ Style/Documentation: - 'recipes/identity_registration.rb' - 'recipes/libvirt_rbd.rb' - 'recipes/nova-setup.rb' + - 'recipes/placement_api.rb' # Offense count: 1 # Configuration parameters: MinBodyLength. @@ -53,3 +55,10 @@ Style/GuardClause: Style/Next: Exclude: - 'recipes/libvirt.rb' + +# Offense count: 8 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline. +# SupportedStyles: single_quotes, double_quotes +Style/StringLiterals: + Enabled: false diff --git a/attributes/default.rb b/attributes/default.rb index 89468de7..26366a14 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -124,14 +124,24 @@ default['openstack']['compute']['api']['auth']['version'] = node['openstack']['a # A PEM encoded Certificate Authority to use when verifying HTTPs connections. default['openstack']['compute']['api']['auth']['cafile'] = nil -# Keystone PKI signing directories -default['openstack']['compute']['api']['auth']['cache_dir'] = '/var/cache/nova/api' +# Placement API settings +default['openstack']['placement']['ssl']['enabled'] = false +default['openstack']['placement']['ssl']['certfile'] = '' +default['openstack']['placement']['ssl']['chainfile'] = '' +default['openstack']['placement']['ssl']['keyfile'] = '' +default['openstack']['placement']['ssl']['ca_certs_path'] = '' +default['openstack']['placement']['ssl']['cert_required'] = false +default['openstack']['placement']['ssl']['protocol'] = '' +default['openstack']['placement']['ssl']['ciphers'] = '' +# Platform specific settings case platform_family when 'rhel' # :pragma-foodcritic: ~FC024 - won't fix this default['openstack']['compute']['platform'] = { 'api_os_compute_packages' => ['openstack-nova-api'], 'api_os_compute_service' => 'openstack-nova-api', + 'api_placement_packages' => ['nova-placement-api'], + 'api_placement_service' => 'nova-placement-api', 'memcache_python_packages' => ['python-memcached'], 'compute_api_metadata_packages' => ['openstack-nova-api'], 'compute_api_metadata_service' => 'openstack-nova-metadata-api', @@ -165,6 +175,8 @@ when 'debian' default['openstack']['compute']['platform'] = { 'api_os_compute_packages' => ['nova-api-os-compute'], 'api_os_compute_service' => 'nova-api-os-compute', + 'api_placement_packages' => ['nova-placement-api'], + 'api_placement_service' => 'nova-placement-api', 'memcache_python_packages' => ['python-memcache'], 'compute_api_metadata_packages' => ['nova-api-metadata'], 'compute_api_metadata_service' => 'nova-api-metadata', @@ -237,6 +249,10 @@ end default['openstack']['endpoints'][type]['compute-serial-proxy']['port'] = '6083' default['openstack']['endpoints'][type]['compute-serial-proxy']['path'] = '/' default['openstack']['endpoints'][type]['compute-serial-proxy']['host'] = '127.0.0.1' + # The OpenStack Compute (Nova) Placement API endpoint + default['openstack']['endpoints'][type]['placement-api']['port'] = '8778' + default['openstack']['endpoints'][type]['placement-api']['path'] = '' + default['openstack']['endpoints'][type]['placement-api']['host'] = '127.0.0.1' end default['openstack']['bind_service']['all']['compute-serial-proxy']['host'] = '127.0.0.1' default['openstack']['bind_service']['all']['compute-vnc-proxy']['host'] = '127.0.0.1' @@ -247,3 +263,5 @@ default['openstack']['bind_service']['all']['compute-serial-proxy']['port'] = '6 default['openstack']['bind_service']['all']['compute-novnc']['port'] = '6080' default['openstack']['bind_service']['all']['compute-metadata-api']['port'] = '8775' default['openstack']['bind_service']['all']['compute-api']['port'] = '8774' +default['openstack']['bind_service']['all']['placement-api']['port'] = '8778' +default['openstack']['bind_service']['all']['placement-api']['host'] = '127.0.0.1' diff --git a/attributes/nova_conf.rb b/attributes/nova_conf.rb index 7fe63a9d..5b0dd814 100644 --- a/attributes/nova_conf.rb +++ b/attributes/nova_conf.rb @@ -20,7 +20,6 @@ default['openstack']['compute']['conf'].tap do |conf| conf['DEFAULT']['dns_server'] = '8.8.8.8' # [] in docs # [keystone_authtoken] - conf['keystone_authtoken']['signing_dir'] = '/var/cache/nova/api' conf['keystone_authtoken']['auth_type'] = 'v3password' conf['keystone_authtoken']['region_name'] = node['openstack']['region'] conf['keystone_authtoken']['username'] = 'nova' @@ -59,4 +58,12 @@ default['openstack']['compute']['conf'].tap do |conf| # [oslo_concurrency] section conf['oslo_concurrency']['lock_path'] = "#{node['openstack']['compute']['conf']['DEFAULT']['state_path']}/lock" + + # [placement] section + conf['placement']['auth_type'] = 'password' + conf['placement']['os_region_name'] = node['openstack']['region'] + conf['placement']['username'] = 'placement' + conf['placement']['user_domain_name'] = 'Default' + conf['placement']['project_domain_name'] = 'Default' + conf['placement']['project_name'] = 'service' end diff --git a/recipes/api-os-compute.rb b/recipes/api-os-compute.rb index 3dacf288..c7fa8ffc 100644 --- a/recipes/api-os-compute.rb +++ b/recipes/api-os-compute.rb @@ -26,12 +26,6 @@ include_recipe 'openstack-compute::nova-common' platform_options = node['openstack']['compute']['platform'] -directory ::File.dirname(node['openstack']['compute']['conf']['keystone_authtoken']['signing_dir']) do - owner node['openstack']['compute']['user'] - group node['openstack']['compute']['group'] - mode 00700 -end - platform_options['api_os_compute_packages'].each do |pkg| package pkg do options platform_options['package_overrides'] diff --git a/recipes/identity_registration.rb b/recipes/identity_registration.rb index b6872586..d2b8fe95 100644 --- a/recipes/identity_registration.rb +++ b/recipes/identity_registration.rb @@ -31,9 +31,15 @@ interfaces = { internal: { url: internal_endpoint('compute-api') }, admin: { url: admin_endpoint('compute-api') } } +placement_interfaces = { + public: { url: public_endpoint('placement-api') }, + internal: { url: internal_endpoint('placement-api') } +} auth_url = ::URI.decode identity_admin_endpoint.to_s service_pass = get_password 'service', 'openstack-compute' service_user = node['openstack']['compute']['conf']['keystone_authtoken']['username'] +placement_service_pass = get_password 'service', 'openstack-placement' +placement_service_user = node['openstack']['compute']['conf']['placement']['username'] service_role = node['openstack']['compute']['service_role'] service_project_name = node['openstack']['compute']['conf']['keystone_authtoken']['project_name'] service_domain_name = node['openstack']['compute']['conf']['keystone_authtoken']['user_domain_name'] @@ -52,15 +58,20 @@ connection_params = { openstack_username: admin_user, openstack_api_key: admin_pass, openstack_project_name: admin_project, - openstack_domain_name: admin_domain + openstack_domain_name: admin_domain } -# Register Compute Service +# Register Compute Services openstack_service 'nova' do type 'compute' connection_params connection_params end +openstack_service 'nova-placement' do + type 'placement' + connection_params connection_params +end + interfaces.each do |interface, res| # Register Compute Endpoints openstack_endpoint 'compute' do @@ -72,12 +83,22 @@ interfaces.each do |interface, res| end end -# Register Service Tenant +placement_interfaces.each do |interface, res| + openstack_endpoint 'placement' do + service_name 'nova-placement' + interface interface.to_s + url res[:url].to_s + region region + connection_params connection_params + end +end + +# Register Service Project openstack_project service_project_name do connection_params connection_params end -# Register Service User +# Register Service Users openstack_user service_user do project_name service_project_name role_name service_role @@ -85,18 +106,27 @@ openstack_user service_user do connection_params connection_params end -## Grant Service role to Service User for Service Tenant ## -openstack_user service_user do - role_name service_role +openstack_user placement_service_user do project_name service_project_name + role_name service_role + password placement_service_pass connection_params connection_params - action :grant_role end -openstack_user service_user do - domain_name service_domain_name - role_name service_role - user_name service_user - connection_params connection_params - action :grant_domain +## Grant Service role to Service Users for Service Project ## +[service_user, placement_service_user].each do |user| + openstack_user user do + role_name service_role + project_name service_project_name + connection_params connection_params + action :grant_role + end + + openstack_user user do + domain_name service_domain_name + role_name service_role + user_name user + connection_params connection_params + action :grant_domain + end end diff --git a/recipes/nova-common.rb b/recipes/nova-common.rb index ae8b18ee..7363cf7b 100644 --- a/recipes/nova-common.rb +++ b/recipes/nova-common.rb @@ -155,6 +155,10 @@ node.default['openstack']['compute']['conf_secrets'] .[]('keystone_authtoken')['password'] = get_password 'service', 'openstack-compute' +node.default['openstack']['compute']['conf_secrets'] + .[]('placement')['password'] = + get_password 'service', 'openstack-placement' + node.default['openstack']['compute']['conf'].tap do |conf| conf['DEFAULT']['iscsi_helper'] = platform_options['iscsi_helper'] # conf['DEFAULT']['scheduler_default_filters'] = node['openstack']['compute']['scheduler']['default_filters'].join(',') @@ -186,6 +190,9 @@ node.default['openstack']['compute']['conf'].tap do |conf| # [keystone_authtoken] section conf['keystone_authtoken']['auth_url'] = auth_url + # [placement] section + conf['placement']['auth_url'] = auth_url + # [glance] section conf['glance']['api_servers'] = "#{image_endpoint.scheme}://#{image_endpoint.host}:#{image_endpoint.port}" diff --git a/recipes/placement_api.rb b/recipes/placement_api.rb new file mode 100644 index 00000000..b2c94f12 --- /dev/null +++ b/recipes/placement_api.rb @@ -0,0 +1,71 @@ +# encoding: UTF-8 +# +# Cookbook Name:: openstack-compute +# Recipe:: placement-api +# +# Copyright 2017, OpenStack Foundation +# +# 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. +# + +class ::Chef::Recipe + include ::Openstack +end + +include_recipe 'openstack-compute::nova-common' + +platform_options = node['openstack']['compute']['platform'] + +platform_options['api_placement_packages'].each do |pkg| + package pkg do + options platform_options['package_overrides'] + action :upgrade + end +end + +nova_user = node['openstack']['compute']['user'] +nova_group = node['openstack']['compute']['group'] +execute 'placement-api: nova-manage api_db sync' do + timeout node['openstack']['compute']['dbsync_timeout'] + user nova_user + group nova_group + command 'nova-manage api_db sync' + action :run +end + +service 'disable nova-placement-api service' do + service_name platform_options['api_placement_service'] + supports status: true, restart: true + action [:disable, :stop] +end + +bind_service = node['openstack']['bind_service']['all']['placement-api'] + +web_app 'placement-api' do + template 'wsgi-template.conf.erb' + daemon_process 'placement-api' + server_host bind_service['host'] + server_port bind_service['port'] + server_entry '/usr/bin/nova-placement-api' + log_dir node['apache']['log_dir'] + user node['openstack']['compute']['user'] + group node['openstack']['compute']['group'] + use_ssl node['openstack']['placement']['ssl']['enabled'] + cert_file node['openstack']['placement']['ssl']['certfile'] + chain_file node['openstack']['placement']['ssl']['chainfile'] + key_file node['openstack']['placement']['ssl']['keyfile'] + ca_certs_path node['openstack']['placement']['ssl']['ca_certs_path'] + cert_required node['openstack']['placement']['ssl']['cert_required'] + protocol node['openstack']['placement']['ssl']['protocol'] + ciphers node['openstack']['placement']['ssl']['ciphers'] +end diff --git a/spec/api-os-compute_spec.rb b/spec/api-os-compute_spec.rb index 1cd9bfae..9c19e265 100644 --- a/spec/api-os-compute_spec.rb +++ b/spec/api-os-compute_spec.rb @@ -14,14 +14,6 @@ describe 'openstack-compute::api-os-compute' do include_examples 'expect_creates_nova_lock_dir' include_examples 'expect_creates_api_paste_template' - it 'creates the /var/cache/nova directory' do - expect(chef_run).to create_directory('/var/cache/nova').with( - user: 'nova', - group: 'nova', - mode: 0700 - ) - end - it do expect(chef_run).to run_execute('nova-manage api_db sync') .with(timeout: 3600, diff --git a/spec/identity_registration_spec.rb b/spec/identity_registration_spec.rb index 95f83c1b..5e367eef 100644 --- a/spec/identity_registration_spec.rb +++ b/spec/identity_registration_spec.rb @@ -26,6 +26,11 @@ describe 'openstack-compute::identity_registration' do role_name = 'admin' password = 'nova-pass' domain_name = 'Default' + placement_service_name = 'nova-placement' + placement_service_type = 'placement' + placement_service_user = 'placement' + placement_password = 'placement-pass' + placement_url = 'http://127.0.0.1:8778' it "registers #{project_name} Project" do expect(chef_run).to create_openstack_project( @@ -44,9 +49,18 @@ describe 'openstack-compute::identity_registration' do ) end + it "registers placement service" do + expect(chef_run).to create_openstack_service( + placement_service_name + ).with( + connection_params: connection_params, + type: placement_service_type + ) + end + context "registers #{service_name} endpoint" do %w(admin internal public).each do |interface| - it "#{interface} endpoint with default values" do + it "creates #{interface} endpoint with default values" do expect(chef_run).to create_openstack_endpoint( service_type ).with( @@ -60,7 +74,23 @@ describe 'openstack-compute::identity_registration' do end end - it 'registers service user' do + context "registers placement endpoint" do + %w(internal public).each do |interface| + it "creates #{interface} endpoint with default values" do + expect(chef_run).to create_openstack_endpoint( + placement_service_type + ).with( + service_name: placement_service_name, + # interface: interface, + url: placement_url, + region: region, + connection_params: connection_params + ) + end + end + end + + it 'registers nova service user' do expect(chef_run).to create_openstack_user( service_user ).with( @@ -71,25 +101,39 @@ describe 'openstack-compute::identity_registration' do ) end - it do - expect(chef_run).to grant_domain_openstack_user( - service_user + it 'registers placement service user' do + expect(chef_run).to create_openstack_user( + placement_service_user ).with( - domain_name: domain_name, + project_name: project_name, role_name: role_name, + password: placement_password, connection_params: connection_params ) end - it do - expect(chef_run).to grant_role_openstack_user( - service_user - ).with( - project_name: project_name, - role_name: role_name, - password: password, - connection_params: connection_params - ) + context "grants user roles" do + [service_user, placement_service_user].each do |user_name| + it do + expect(chef_run).to grant_domain_openstack_user( + user_name + ).with( + domain_name: domain_name, + role_name: role_name, + connection_params: connection_params + ) + end + + it do + expect(chef_run).to grant_role_openstack_user( + user_name + ).with( + project_name: project_name, + role_name: role_name, + connection_params: connection_params + ) + end + end end end end diff --git a/spec/nova-common_spec.rb b/spec/nova-common_spec.rb index 620d1a23..eda60770 100644 --- a/spec/nova-common_spec.rb +++ b/spec/nova-common_spec.rb @@ -136,6 +136,23 @@ describe 'openstack-compute::nova-common' do end end + context 'placement' do + it 'has correct authentication settings' do + [ + 'auth_type = password', + 'os_region_name = RegionOne', + 'password = placement-pass', + 'username = placement', + 'project_name = service', + 'user_domain_name = Default', + 'project_domain_name = Default' + ].each do |line| + expect(chef_run).to render_config_file(file.name)\ + .with_section_content('placement', /^#{Regexp.quote(line)}$/) + end + end + end + it 'uses default values for attributes' do [ diff --git a/spec/placement_api_spec.rb b/spec/placement_api_spec.rb new file mode 100644 index 00000000..e2b05300 --- /dev/null +++ b/spec/placement_api_spec.rb @@ -0,0 +1,34 @@ +# encoding: UTF-8 + +require_relative 'spec_helper' + +describe 'openstack-compute::placement_api' do + describe 'ubuntu' do + let(:runner) { ChefSpec::SoloRunner.new(UBUNTU_OPTS) } + let(:node) { runner.node } + let(:chef_run) { runner.converge(described_recipe) } + + include_context 'compute_stubs' + + it "includes nova-common recipe" do + expect(chef_run).to include_recipe 'openstack-compute::nova-common' + end + + it "upgrades package nova-placement-api" do + expect(chef_run).to upgrade_package 'nova-placement-api' + end + + it "executes placement-api: nova-manage api_db sync" do + expect(chef_run).to run_execute('placement-api: nova-manage api_db sync').with( + timeout: 3600, + user: 'nova', + group: 'nova', + command: 'nova-manage api_db sync' + ) + end + + it "disables nova-placement-api service" do + expect(chef_run).to disable_service 'disable nova-placement-api service' + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b3ce056f..1982d392 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -70,6 +70,9 @@ shared_context 'compute_stubs' do allow_any_instance_of(Chef::Recipe).to receive(:get_password) .with('service', 'openstack-network') .and_return('neutron-pass') + allow_any_instance_of(Chef::Recipe).to receive(:get_password) + .with('service', 'openstack-placement') + .and_return('placement-pass') allow_any_instance_of(Chef::Recipe).to receive(:get_password) .with('service', 'rbd_block_storage') .and_return 'cinder-rbd-pass' @@ -82,6 +85,7 @@ shared_context 'compute_stubs' do # stub_command('nova-manage network list | grep 192.168.100.0/24').and_return(false) # stub_command('nova-manage network list | grep 192.168.200.0/24').and_return(false) # stub_command("nova-manage floating list |grep -E '.*([0-9]{1,3}[.]){3}[0-9]{1,3}*'").and_return(false) + stub_command("/usr/sbin/apache2 -t").and_return(true) stub_command('virsh net-list | grep -q default').and_return(true) stub_command('ovs-vsctl br-exists br-int').and_return(true) stub_command('ovs-vsctl br-exists br-tun').and_return(true) diff --git a/templates/default/wsgi-template.conf.erb b/templates/default/wsgi-template.conf.erb new file mode 100644 index 00000000..a05f5ada --- /dev/null +++ b/templates/default/wsgi-template.conf.erb @@ -0,0 +1,41 @@ +<%= node["openstack"]["compute"]["custom_template_banner"] %> + +Listen <%= @params[:server_host] %>:<%= @params[:server_port] %> + +:<%= @params[:server_port] %>> + WSGIDaemonProcess <%= @params[:daemon_process] %> processes=2 threads=10 user=<%= @params[:user] %> group=<%= @params[:group] %> display-name=%{GROUP} + WSGIProcessGroup <%= @params[:daemon_process] %> + WSGIScriptAlias / <%= @params[:server_entry] %> + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + + + Require all granted + + + ErrorLogFormat "%{cu}t %M" + ErrorLog <%= @params[:log_dir] %>/<%= @params[:daemon_process] %>_error.log + CustomLog <%= @params[:log_dir] %>/<%= @params[:daemon_process] %>_access.log combined +<% if [true, 'true', 'True'].include?(@params[:log_debug]) -%> + LogLevel debug +<% end -%> + +<% if @params[:use_ssl] -%> + SSLEngine On + SSLCertificateFile <%= @params[:cert_file] %> + SSLCertificateKeyFile <%= @params[:key_file] %> + SSLCACertificatePath <%= @params[:ca_certs_path] %> +<% if @params[:chain_file] %> + SSLCertificateChainFile <%= @params[:chain_file] %> +<% end -%> + SSLProtocol <%= @params[:protocol] %> +<% if @params[:ciphers] -%> + SSLCipherSuite <%= @params[:ciphers] %> +<% end -%> +<% if @params[:cert_required] -%> + SSLVerifyClient require +<% end -%> +<% end -%> + + +WSGISocketPrefix /var/run/apache2