Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,36 @@
elasticsearch_service 'elasticsearch'
```

**Restart Configuration**

Check failure on line 235 in README.md

View workflow job for this annotation

GitHub Actions / lint-unit / runner / markdownlint

Emphasis used instead of a heading

README.md:235 MD036/no-emphasis-as-heading Emphasis used instead of a heading [Context: "Restart Configuration"] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md036.md

Check failure on line 235 in README.md

View workflow job for this annotation

GitHub Actions / lint-unit / runner / markdownlint

Emphasis used instead of a heading

README.md:235 MD036/no-emphasis-as-heading Emphasis used instead of a heading [Context: "Restart Configuration"] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md036.md

You can configure systemd restart behavior using the `restart_policy` and `restart_sec` properties:

```ruby
elasticsearch_service 'elasticsearch' do
restart_policy 'on-failure' # Restart only on failure
restart_sec 30 # Wait 30 seconds before restart
end
```

```ruby
elasticsearch_service 'elasticsearch' do
restart_policy 'always' # Always restart
restart_sec '5min' # Wait 5 minutes before restart
end
```

Valid restart policies:
- `''` (empty string) - No automatic restart (default, maintains backward compatibility)

Check failure on line 254 in README.md

View workflow job for this annotation

GitHub Actions / lint-unit / runner / markdownlint

Lists should be surrounded by blank lines

README.md:254 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- `''` (empty string) - No aut..."] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md032.md

Check failure on line 254 in README.md

View workflow job for this annotation

GitHub Actions / lint-unit / runner / markdownlint

Lists should be surrounded by blank lines

README.md:254 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- `''` (empty string) - No aut..."] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md032.md
- `'no'` - Never restart
- `'always'` - Always restart regardless of exit status
- `'on-success'` - Restart only when process exits cleanly
- `'on-failure'` - Restart when process exits with non-zero code, killed by signal, timeout, or watchdog
- `'on-abnormal'` - Restart when process is terminated by signal, timeout, or watchdog
- `'on-abort'` - Restart when process exits due to uncaught signal
- `'on-watchdog'` - Restart when watchdog timeout occurs

The `restart_sec` property accepts either an integer (seconds) or a systemd time span string (e.g., "5min", "30s", "1m 30s").

If you'd like to skip init scripts and systemd scripts, simply pass `nil` for
the template file (init_source or systemd_source) and this cookbook will
entirely skip trying to setup those scripts. Combined with changing the default
Expand Down
79 changes: 51 additions & 28 deletions resources/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
[Symbol, String, Array],
default: [:enable, :start]

property :restart_policy,
String,
default: '',
regex: /^(no|always|on-success|on-failure|on-abnormal|on-abort|on-watchdog)?$/,
description: 'Systemd restart policy. Valid values: no, always, on-success, on-failure, on-abnormal, on-abort, on-watchdog. Defaults to empty string (no restart).'

property :restart_sec,
[Integer, String],
description: 'Configures the time to sleep before restarting a service (seconds). Takes an integer or time span value (e.g., "5min 20s").'

action :configure do
es_user = find_es_resource(Chef.run_context, :elasticsearch_user, new_resource)
es_conf = find_es_resource(Chef.run_context, :elasticsearch_configure, new_resource)
Expand All @@ -30,6 +40,46 @@

default_conf_dir = platform_family?('rhel', 'amazon') ? '/etc/sysconfig' : '/etc/default'

# Build service configuration with optional restart settings
service_config = {
Type: 'notify',
RuntimeDirectory: 'elasticsearch',
PrivateTmp: 'true',
Environment: [
"ES_HOME=#{es_conf.path_home}",
'ES_PATH_CONF=/etc/elasticsearch',
"PID_DIR=#{es_conf.path_pid}",
'ES_SD_NOTIFY=true',
],
EnvironmentFile: "-#{default_conf_dir}/#{new_resource.service_name}",
WorkingDirectory: "#{es_conf.path_home}",
User: es_user.username,
Group: es_user.groupname,
ExecStart: "#{es_conf.path_home}/bin/systemd-entrypoint -p ${PID_DIR}/elasticsearch.pid --quiet",
StandardOutput: 'journal',
StandardError: 'inherit',
LimitNOFILE: '65535',
LimitNPROC: '4096',
LimitAS: 'infinity',
LimitFSIZE: 'infinity',
TimeoutStopSec: '0',
KillSignal: 'SIGTERM',
KillMode: 'process',
SendSIGKILL: 'no',
SuccessExitStatus: '143',
TimeoutStartSec: '900',
}

# Add restart policy if specified
unless new_resource.restart_policy.empty?
service_config[:Restart] = new_resource.restart_policy
end

# Add restart delay if specified
if new_resource.restart_sec
service_config[:RestartSec] = new_resource.restart_sec
end

systemd_unit new_resource.service_name do
content(
Unit: {
Expand All @@ -38,34 +88,7 @@
Wants: 'network-online.target',
After: 'network-online.target',
},
Service: {
Type: 'notify',
RuntimeDirectory: 'elasticsearch',
PrivateTmp: 'true',
Environment: [
"ES_HOME=#{es_conf.path_home}",
'ES_PATH_CONF=/etc/elasticsearch',
"PID_DIR=#{es_conf.path_pid}",
'ES_SD_NOTIFY=true',
],
EnvironmentFile: "-#{default_conf_dir}/#{new_resource.service_name}",
WorkingDirectory: "#{es_conf.path_home}",
User: es_user.username,
Group: es_user.groupname,
ExecStart: "#{es_conf.path_home}/bin/systemd-entrypoint -p ${PID_DIR}/elasticsearch.pid --quiet",
StandardOutput: 'journal',
StandardError: 'inherit',
LimitNOFILE: '65535',
LimitNPROC: '4096',
LimitAS: 'infinity',
LimitFSIZE: 'infinity',
TimeoutStopSec: '0',
KillSignal: 'SIGTERM',
KillMode: 'process',
SendSIGKILL: 'no',
SuccessExitStatus: '143',
TimeoutStartSec: '900',
},
Service: service_config,
Install: {
WantedBy: 'multi-user.target',
}
Expand Down
57 changes: 57 additions & 0 deletions spec/service_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require_relative 'spec_helper'

describe 'elasticsearch_service' do
before { stub_resources }

supported_platforms.each do |platform, versions|
versions.each do |version|
context "on #{platform.capitalize} #{version}" do
let(:chef_run) do
ChefSpec::ServerRunner.new(platform: platform, version: version, step_into: ['elasticsearch_service']) do |node, server|
node_resources(node)
stub_chef_zero(platform, version, server)
end.converge('test::restart_policy')
end

it 'creates systemd unit with restart policy' do
expect(chef_run).to create_systemd_unit('elasticsearch').with(
content: hash_including(
Service: hash_including(
Restart: 'on-failure',
RestartSec: 30
)
)
)
end

it 'enables and starts the elasticsearch service' do
expect(chef_run).to enable_service('elasticsearch')
expect(chef_run).to start_service('elasticsearch')
end
end
end
end

# Test default behavior (no restart)
context 'with default configuration' do
let(:chef_run) do
ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '20.04', step_into: ['elasticsearch_service']) do |node, server|
node_resources(node)
stub_chef_zero('ubuntu', '20.04', server)
end.converge_dsl('test') do
elasticsearch_user 'elasticsearch'
elasticsearch_install 'elasticsearch' do
type 'package'
end
elasticsearch_configure 'elasticsearch'
elasticsearch_service 'elasticsearch'
end
end

it 'creates systemd unit without restart policy' do
systemd_unit = chef_run.systemd_unit('elasticsearch')
expect(systemd_unit.content[:Service]).not_to have_key(:Restart)
expect(systemd_unit.content[:Service]).not_to have_key(:RestartSec)
end
end
end
21 changes: 21 additions & 0 deletions test/fixtures/cookbooks/test/recipes/restart_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# test fixture to validate restart_policy functionality

# Basic installation and user setup
elasticsearch_user 'elasticsearch'

elasticsearch_install 'elasticsearch' do
type 'package'
end

elasticsearch_configure 'elasticsearch' do
allocated_memory '256m'
configuration('node.name' => 'restart_test_node')
action :manage
end

# Test service with restart policy
elasticsearch_service 'elasticsearch' do
restart_policy 'on-failure'
restart_sec 30
service_actions [:enable, :start]
end
38 changes: 38 additions & 0 deletions test/integration/default/controls/restart_policy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
control 'Service restart configuration' do
impact 1.0
title 'Elasticsearch service restart policy configuration'
desc 'Verify that restart policy is correctly configured in systemd unit'

# Test that the systemd service file exists
describe file('/etc/systemd/system/elasticsearch.service') do
it { should exist }
end

# Test restart policy configuration if the test recipe was used
if file('/etc/systemd/system/elasticsearch.service').exist?
service_content = file('/etc/systemd/system/elasticsearch.service').content

# Check if this is the restart_policy test
if service_content.include?('Restart=on-failure')
describe 'Elasticsearch service restart configuration' do
it 'should have restart policy configured' do
expect(service_content).to match(/^Restart=on-failure$/)
end

it 'should have restart delay configured' do
expect(service_content).to match(/^RestartSec=30$/)
end
end
else
describe 'Elasticsearch service default configuration' do
it 'should not have restart policy by default' do
expect(service_content).not_to match(/^Restart=/)
end

it 'should not have restart delay by default' do
expect(service_content).not_to match(/^RestartSec=/)
end
end
end
end
end
Loading