-
Notifications
You must be signed in to change notification settings - Fork 110
Replace cfn-hup on compute nodes with systemd timers to signal updates #3070
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
61ff8e4
d7a8aea
0c05f11
e568ae2
329c17c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| [Unit] | ||
| Description=Check file modification time every minute | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The description must be more specific: it must be more clear that this is a timer configured by pcluster (add this info in the description and in the file name) and the goal of the timer (checks file modifications, which files, why?) |
||
|
|
||
| [Timer] | ||
| AccuracySec=1s | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The accuracy has an impact on CPU wake-ups. See https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html |
||
| OnActiveSec=60sec | ||
| OnUnitActiveSec=60sec | ||
| Unit=check-update.service | ||
|
|
||
| [Install] | ||
| WantedBy=timers.target | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,3 +12,7 @@ | |
| # limitations under the License. | ||
|
|
||
| include_recipe 'aws-parallelcluster-computefleet::fleet_status' | ||
|
|
||
| if ['ComputeFleet'].include?(node['cluster']['node_type']) | ||
| include_recipe 'aws-parallelcluster-computefleet::config_check_update_systemd_service' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # | ||
| # Cookbook:: aws-parallelcluster-slurm | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong cookbook. Curreently, the recipe i sin cookbook Also, what about moving this recipe to cookbook |
||
| # Recipe:: config_compute | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix recipe name |
||
| # | ||
| # Copyright:: 2013-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and in other files: fix copyright year with |
||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the | ||
| # License. A copy of the License is located at | ||
| # | ||
| # http://aws.amazon.com/apache2.0/ | ||
| # | ||
| # or in the "LICENSE.txt" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES | ||
| # OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| template '/etc/systemd/system/check-update.service' do | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, above and below: the name of the service and the corresponding timer must be more talkative, expressing that they are pcluster services related to the cluster updates |
||
| source 'check_update/check-update.service.erb' | ||
| owner 'root' | ||
| group 'root' | ||
| mode '0644' | ||
| end | ||
|
|
||
| cookbook_file '/etc/systemd/system/check-update.timer' do | ||
| source 'check_update/check-update.timer' | ||
| owner 'root' | ||
| group 'root' | ||
| mode '0644' | ||
| action :create | ||
| end | ||
|
|
||
| file node['cluster']['shared_update_path'] do | ||
| content '' | ||
| owner 'root' | ||
| group 'root' | ||
| mode '0644' | ||
| action :create_if_missing | ||
| end | ||
|
|
||
| file node['cluster']['update_checkpoint'] do | ||
| content '' | ||
| owner 'root' | ||
| group 'root' | ||
| mode '0644' | ||
| action :create_if_missing | ||
| end | ||
|
|
||
| service 'check-update.timer' do | ||
| action [:enable, :start] | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| require 'spec_helper' | ||
|
|
||
| describe 'aws-parallelcluster-computefleet::config_check_update_systemd_service' do | ||
| for_all_oses do |platform, version| | ||
| context "on #{platform}#{version}" do | ||
| cached(:chef_run) do | ||
| runner = runner(platform: platform, version: version) do |node| | ||
| node.override['cluster']['node_type'] = 'ComputeFleet' | ||
| end | ||
| runner.converge(described_recipe) | ||
| end | ||
| cached(:node) { chef_run.node } | ||
|
|
||
| it 'creates the check-update.service template' do | ||
| is_expected.to create_template('/etc/systemd/system/check-update.service') | ||
| .with(source: 'check_update/check-update.service.erb') | ||
| .with(owner: 'root') | ||
| .with(group: 'root') | ||
| .with(mode: '0644') | ||
| end | ||
|
|
||
| it 'creates the check-update.timer file' do | ||
| is_expected.to create_cookbook_file('/etc/systemd/system/check-update.timer') | ||
| .with(source: 'check_update/check-update.timer') | ||
| .with(owner: 'root') | ||
| .with(group: 'root') | ||
| .with(mode: '0644') | ||
| end | ||
|
|
||
| it 'creates the shared update path file if missing' do | ||
| is_expected.to create_file_if_missing(node['cluster']['shared_update_path']) | ||
| .with(content: '') | ||
| .with(owner: 'root') | ||
| .with(group: 'root') | ||
| .with(mode: '0644') | ||
| end | ||
|
|
||
| it 'creates the local update checkpoint file if missing' do | ||
| is_expected.to create_file_if_missing(node['cluster']['update_checkpoint']) | ||
| .with(content: '') | ||
| .with(owner: 'root') | ||
| .with(group: 'root') | ||
| .with(mode: '0644') | ||
| end | ||
|
|
||
| it 'enables and starts the check-update.timer service' do | ||
| is_expected.to enable_service('check-update.timer') | ||
| is_expected.to start_service('check-update.timer') | ||
| end | ||
|
|
||
| describe 'check-update.service template content' do | ||
| it 'has Type=oneshot to prevent concurrent executions' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content('Type=oneshot') | ||
| end | ||
|
|
||
| it 'has TimeoutStartSec=30 to handle NFS hangs' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content('TimeoutStartSec=30') | ||
| end | ||
|
|
||
| it 'exits gracefully if shared file does not exist' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content('[ ! -f "$SHARED_FILE" ] && exit 0') | ||
| end | ||
|
|
||
| it 'exits gracefully if cat fails' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content('CURRENT_UPDATE=$(cat "$SHARED_FILE") || exit 0') | ||
| end | ||
|
|
||
| it 'writes checkpoint before running update action' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content('echo "$CURRENT_UPDATE" > "$LOCAL_CHECKPOINT" && ') | ||
| end | ||
|
|
||
| it 'references the correct shared update path' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content("SHARED_FILE=\"#{node['cluster']['shared_update_path']}\"") | ||
| end | ||
|
|
||
| it 'references the correct local checkpoint path' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content("LOCAL_CHECKPOINT=\"#{node['cluster']['update_checkpoint']}\"") | ||
| end | ||
|
|
||
| it 'calls cfn-hup-update-action.sh when update is needed' do | ||
| is_expected.to render_file('/etc/systemd/system/check-update.service') | ||
| .with_content("#{node['cluster']['scripts_dir']}/cfn-hup-update-action.sh") | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| [Unit] | ||
| Description=Check for recent file modifications | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| [Service] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are missing logs for the logic executed by this service. Also, the logic should log more information:
All log lines must be timestamped with millis resolution. |
||
| Type=oneshot | ||
| TimeoutStartSec=30 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose this timeout is here to prevent the service being stuck in case of file system unresponsiveness. According to the official documentation for TimeoutStartSec:
So the timeout covers the whole start logic. The start logic here includes the execution of If you agree with this risk, I suggest to configure the timeout logic differently:
|
||
| ExecStart=/bin/bash -c '\ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To improve maintainability we must move this logic into a dedicated script and have the unit file invoke it |
||
| SHARED_FILE="<%= node['cluster']['shared_update_path'] %>"; \ | ||
| LOCAL_CHECKPOINT="<%= node['cluster']['update_checkpoint'] %>"; \ | ||
| \ | ||
| [ ! -f "$SHARED_FILE" ] && exit 0; \ | ||
| \ | ||
| CURRENT_UPDATE=$(cat "$SHARED_FILE") || exit 0; \ | ||
| LAST_APPLIED=$([ -f "$LOCAL_CHECKPOINT" ] && cat "$LOCAL_CHECKPOINT" || echo ""); \ | ||
| \ | ||
| if [ "$CURRENT_UPDATE" != "$LAST_APPLIED" ]; then \ | ||
| echo "$CURRENT_UPDATE" > "$LOCAL_CHECKPOINT" && <%= node['cluster']['scripts_dir'] %>/cfn-hup-update-action.sh; \ | ||
| fi' | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This service is triggered by a timer. What is the point of having |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,10 @@ | |
| default['cluster']['log_base_dir'] = '/var/log/parallelcluster' | ||
| default['cluster']['etc_dir'] = '/etc/parallelcluster' | ||
|
|
||
| # Shared file used to manage inplace updates | ||
| default['cluster']['shared_update_path'] = "#{node['cluster']['shared_dir']}/check_update" | ||
| default['cluster']['update_checkpoint'] = "#{node['cluster']['scripts_dir']}/update_checkpoint" | ||
|
Comment on lines
+13
to
+14
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest to use more talkative names, such as With such names for the attributes we better convey that:
|
||
|
|
||
| # Slurm_plugin_dir is used by slurm cookbook and custom_actions recipe | ||
| default['cluster']['slurm_plugin_dir'] = "#{node['cluster']['etc_dir']}/slurm_plugin" | ||
|
|
||
|
|
@@ -34,6 +38,3 @@ | |
|
|
||
| # Default NFS mount options | ||
| default['cluster']['nfs']['hard_mount_options'] = 'hard,_netdev,noatime' | ||
|
|
||
| # Cluster Updates | ||
| default['cluster']['in_place_update_on_fleet_enabled'] = 'true' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,14 +106,3 @@ def wait_sync_file(path) | |
| timeout 5 | ||
| end | ||
| end | ||
|
|
||
| def cfnhup_enabled? | ||
| # cfn-hup is always enabled on the head node, as it is required to perform cluster updates. | ||
| # cfn-hup can be disabled on compute nodes and login nodes, limiting the cluster update in the sense that | ||
| # live updates on compute and login nodes are not possible. | ||
| node['cluster']['node_type'] == 'HeadNode' || node['cluster']['in_place_update_on_fleet_enabled'] == 'true' | ||
| end | ||
|
|
||
| def cluster_readiness_check_on_update_enabled? | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as https://github.com/aws/aws-parallelcluster-cookbook/pull/3070/changes#r2641117741 I think it is useful to keep a way to skip cluster readiness check through chef attributes. |
||
| node['cluster']['in_place_update_on_fleet_enabled'] == 'true' | ||
| end | ||
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We must surface the value of this change for the user, which is providing better performance.
Also we should surface that the new mechanism relies on shared storage sync between head node and compute fleet.