13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## [18.2.0](https://github.com/theforeman/puppet-foreman/tree/18.2.0) (2021-08-24)

[Full Changelog](https://github.com/theforeman/puppet-foreman/compare/18.1.0...18.2.0)

**Implemented enhancements:**

- Fixes [\#33320](https://projects.theforeman.org/issues/33320) - Refer to FQDN instead of "Foreman server" in SmartProx… [\#988](https://github.com/theforeman/puppet-foreman/pull/988) ([wbclark](https://github.com/wbclark))
- Fixes [\#33277](https://projects.theforeman.org/issues/33277): Change Puma default workers to 1.5 \* CPU, max threads to 5 [\#986](https://github.com/theforeman/puppet-foreman/pull/986) ([ehelms](https://github.com/ehelms))

**Fixed bugs:**

- Fixes [\#33214](https://projects.theforeman.org/issues/33214): Set minimum Puma threads equal to maximum puma threads … [\#984](https://github.com/theforeman/puppet-foreman/pull/984) ([ehelms](https://github.com/ehelms))

## [18.1.0](https://github.com/theforeman/puppet-foreman/tree/18.1.0) (2021-08-04)

[Full Changelog](https://github.com/theforeman/puppet-foreman/compare/18.0.0...18.1.0)
Expand Down
16 changes: 9 additions & 7 deletions lib/puppet/provider/foreman_resource/rest_v3.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,16 @@ def success?(response)
end

def error_message(response)
fqdn = URI::parse(resource[:base_url]).host

explanations = {
'400' => 'Something is wrong with the data sent to Foreman server',
'401' => 'Often this is caused by invalid Oauth credentials',
'404' => 'The requested resource was not found',
'500' => 'Check /var/log/foreman/production.log on Foreman server for detailed information',
'502' => 'The webserver received an invalid response from the backend service. Was Foreman unable to handle the request?',
'503' => 'The webserver was unable to reach the backend service. Is foreman.service running?',
'504' => 'The webserver timed out waiting for a response from the backend service. Is Foreman under unusually heavy load?'
'400' => "Something is wrong with the data sent to Foreman at #{fqdn}",
'401' => "Often this is caused by invalid Oauth credentials sent to Foreman at #{fqdn}",
'404' => "The requested resource was not found in Foreman at #{fqdn}",
'500' => "Check /var/log/foreman/production.log on #{fqdn} for detailed information",
'502' => "The webserver received an invalid response from the backend service. Was Foreman at #{fqdn} unable to handle the request?",
'503' => "The webserver was unable to reach the backend service. Is Foreman running at #{fqdn}?",
'504' => "The webserver timed out waiting for a response from the backend service. Is Foreman at #{fqdn} under unusually heavy load?"
}

if (explanation = explanations[response.code.to_str])
Expand Down
12 changes: 12 additions & 0 deletions manifests/config.pp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@
content => template('foreman/database.yml.erb'),
}

# CPU based calculation is based on https://github.com/puma/puma/blob/master/docs/deployment.md#mri
# Memory based calculation is based on https://docs.gitlab.com/ee/install/requirements.html#puma-settings
$puma_workers = pick(
$foreman::foreman_service_puma_workers,
floor(
min(
$facts['processors']['count'] * 1.5,
($facts['memory']['system']['total_bytes']/(1024 * 1024 * 1024)) - 1.5
)
)
)
$min_puma_threads = pick($foreman::foreman_service_puma_threads_min, $foreman::foreman_service_puma_threads_max)
systemd::dropin_file { 'foreman-service':
filename => 'installer.conf',
unit => "${foreman::foreman_service}.service",
Expand Down
12 changes: 8 additions & 4 deletions manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,15 @@
#
# $cors_domains:: List of domains that show be allowed for Cross-Origin Resource Sharing
#
# $foreman_service_puma_threads_min:: Minimum number of threads for every Puma worker
# $foreman_service_puma_threads_min:: Minimum number of threads for every Puma worker. If no value is specified, this defaults
# to setting min threads to maximum threads. Setting min threads equal to max threads has
# been shown to alleviate memory leaks and in some cases produce better performance.
#
# $foreman_service_puma_threads_max:: Maximum number of threads for every Puma worker
#
# $foreman_service_puma_workers:: Number of workers for Puma
# $foreman_service_puma_workers:: Number of workers for Puma.
# If not set, the value is dynamically calculated based on available number of
# CPUs and memory.
#
# $rails_cache_store:: Set rails cache store
#
Expand Down Expand Up @@ -272,9 +276,9 @@
Optional[Redis::RedisUrl] $dynflow_redis_url = $foreman::params::dynflow_redis_url,
Boolean $hsts_enabled = $foreman::params::hsts_enabled,
Array[Stdlib::HTTPUrl] $cors_domains = $foreman::params::cors_domains,
Integer[0] $foreman_service_puma_threads_min = $foreman::params::foreman_service_puma_threads_min,
Optional[Integer[0]] $foreman_service_puma_threads_min = $foreman::params::foreman_service_puma_threads_min,
Integer[0] $foreman_service_puma_threads_max = $foreman::params::foreman_service_puma_threads_max,
Integer[0] $foreman_service_puma_workers = $foreman::params::foreman_service_puma_workers,
Optional[Integer[0]] $foreman_service_puma_workers = $foreman::params::foreman_service_puma_workers,
Hash[String, Any] $rails_cache_store = $foreman::params::rails_cache_store,
Boolean $keycloak = $foreman::params::keycloak,
String[1] $keycloak_app_name = $foreman::params::keycloak_app_name,
Expand Down
6 changes: 3 additions & 3 deletions manifests/params.pp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
$foreman_service = 'foreman'
$foreman_service_ensure = 'running'
$foreman_service_enable = true
$foreman_service_puma_threads_min = 0
$foreman_service_puma_threads_max = 16
$foreman_service_puma_workers = 2
$foreman_service_puma_threads_min = undef
$foreman_service_puma_threads_max = 5
$foreman_service_puma_workers = undef

# Define job processing service properties
$dynflow_manage_services = true
Expand Down
2 changes: 1 addition & 1 deletion metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "theforeman-foreman",
"version": "18.1.0",
"version": "18.2.0",
"author": "theforeman",
"summary": "Foreman server configuration",
"license": "GPL-3.0+",
Expand Down
15 changes: 13 additions & 2 deletions spec/classes/foreman_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
describe 'foreman' do
on_supported_os.each do |os, facts|
context "on #{os}" do
let(:facts) { facts }
let(:facts) { override_facts(facts, processors: { count: 3 }, memory: { system: { total_bytes: 10_737_418_240}}) }
let(:params) { {} }
let(:apache_user) { facts[:osfamily] == 'Debian' ? 'www-data' : 'apache' }

Expand Down Expand Up @@ -92,7 +92,18 @@
.with_content(/^SocketUser=#{apache_user}$/)
end

it { should contain_systemd__dropin_file('foreman-service').with_filename('installer.conf').with_unit('foreman.service') }
it 'overrides foreman.service systemd service' do
should contain_systemd__dropin_file('foreman-service')
.with_ensure('present')
.with_filename('installer.conf')
.with_unit('foreman.service')
.with_content(%r{^User=foreman$})
.with_content(%r{^Environment=FOREMAN_ENV=production$})
.with_content(%r{^Environment=FOREMAN_HOME=/usr/share/foreman$})
.with_content(%r{^Environment=FOREMAN_PUMA_THREADS_MIN=5$})
.with_content(%r{^Environment=FOREMAN_PUMA_THREADS_MAX=5$})
.with_content(%r{^Environment=FOREMAN_PUMA_WORKERS=4$})
end

it { should contain_apache__vhost('foreman').without_custom_fragment(/Alias/) }

Expand Down
18 changes: 11 additions & 7 deletions spec/unit/foreman_resource_rest_v3_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@
end

describe '#error_message(response)' do
before { expect(resource).to receive(:[]).with(:base_url).and_return(base_url) }

let(:base_url) { 'https://foreman.example.com' }

it 'returns array of errors from JSON' do
expect(provider.error_message(double(:body => '{"error":{"full_messages":["error1","error2"]}}', :code => 'dummycode'))).to eq('error1 error2')
end
Expand All @@ -150,31 +154,31 @@
end

it 'returns message for 400 response' do
expect(provider.error_message(double(:body => '{}', :code => '400', :message => 'Bad Request'))).to eq('Response: 400 Bad Request: Something is wrong with the data sent to Foreman server')
expect(provider.error_message(double(:body => '{}', :code => '400', :message => 'Bad Request'))).to eq('Response: 400 Bad Request: Something is wrong with the data sent to Foreman at foreman.example.com')
end

it 'returns message for 401 response' do
expect(provider.error_message(double(:body => '{}', :code => '401', :message => 'Unauthorized Request'))).to eq('Response: 401 Unauthorized Request: Often this is caused by invalid Oauth credentials')
expect(provider.error_message(double(:body => '{}', :code => '401', :message => 'Unauthorized Request'))).to eq('Response: 401 Unauthorized Request: Often this is caused by invalid Oauth credentials sent to Foreman at foreman.example.com')
end

it 'returns message for 404 response' do
expect(provider.error_message(double(:body => '{}', :code => '404', :message => 'Not Found'))).to eq('Response: 404 Not Found: The requested resource was not found')
expect(provider.error_message(double(:body => '{}', :code => '404', :message => 'Not Found'))).to eq('Response: 404 Not Found: The requested resource was not found in Foreman at foreman.example.com')
end

it 'returns message for 500 response' do
expect(provider.error_message(double(:body => '{}', :code => '500', :message => 'Internal Server Error'))).to eq('Response: 500 Internal Server Error: Check /var/log/foreman/production.log on Foreman server for detailed information')
expect(provider.error_message(double(:body => '{}', :code => '500', :message => 'Internal Server Error'))).to eq('Response: 500 Internal Server Error: Check /var/log/foreman/production.log on foreman.example.com for detailed information')
end

it 'returns message for 502 response' do
expect(provider.error_message(double(:body => '{}', :code => '502', :message => 'Bad Gateway'))).to eq('Response: 502 Bad Gateway: The webserver received an invalid response from the backend service. Was Foreman unable to handle the request?')
expect(provider.error_message(double(:body => '{}', :code => '502', :message => 'Bad Gateway'))).to eq('Response: 502 Bad Gateway: The webserver received an invalid response from the backend service. Was Foreman at foreman.example.com unable to handle the request?')
end

it 'returns message for 503 response' do
expect(provider.error_message(double(:body => '{}', :code => '503', :message => 'Service Unavailable'))).to eq('Response: 503 Service Unavailable: The webserver was unable to reach the backend service. Is foreman.service running?')
expect(provider.error_message(double(:body => '{}', :code => '503', :message => 'Service Unavailable'))).to eq('Response: 503 Service Unavailable: The webserver was unable to reach the backend service. Is Foreman running at foreman.example.com?')
end

it 'returns message for 504 response' do
expect(provider.error_message(double(:body => '{}', :code => '504', :message => 'Gateway Timeout'))).to eq('Response: 504 Gateway Timeout: The webserver timed out waiting for a response from the backend service. Is Foreman under unusually heavy load?')
expect(provider.error_message(double(:body => '{}', :code => '504', :message => 'Gateway Timeout'))).to eq('Response: 504 Gateway Timeout: The webserver timed out waiting for a response from the backend service. Is Foreman at foreman.example.com under unusually heavy load?')
end
end
end
4 changes: 2 additions & 2 deletions templates/foreman.service-overrides.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
User=<%= scope['foreman::user'] %>
Environment=FOREMAN_ENV=<%= scope['foreman::rails_env'] %>
Environment=FOREMAN_HOME=<%= scope['foreman::app_root'] %>
Environment=FOREMAN_PUMA_THREADS_MIN=<%= scope['foreman::foreman_service_puma_threads_min'] %>
Environment=FOREMAN_PUMA_THREADS_MIN=<%= scope['foreman::config::min_puma_threads'] %>
Environment=FOREMAN_PUMA_THREADS_MAX=<%= scope['foreman::foreman_service_puma_threads_max'] %>
Environment=FOREMAN_PUMA_WORKERS=<%= scope['foreman::foreman_service_puma_workers'] %>
Environment=FOREMAN_PUMA_WORKERS=<%= scope['foreman::config::puma_workers'] %>