diff --git a/CHANGELOG.md b/CHANGELOG.md index 45c1db4131..1682d248b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This file is used to list changes made in each version of the AWS ParallelCluste ------ **ENHANCEMENTS** +- Add the configuration parameter `DeploymentSettings/DefaultUserHome` to allow users to move the default user's home directory to `/local/home` instead of `/home` (default). - Add support for installing Intel OneAPI Base Toolkit and HPC Toolkit, and Intel Python. - Intel OneAPI Base Toolkits: 2023.2.0 - Intel OneAPI HPC Toolkits: 2023.2.0 diff --git a/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml b/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml index d9cdd098dd..9e6f5eb351 100644 --- a/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml +++ b/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml @@ -752,3 +752,39 @@ suites: dependencies: - recipe:aws-parallelcluster-platform::directories - resource:spack:setup + - name: default_user_local_home_head_node + run_list: + - recipe[aws-parallelcluster-tests::setup] + - recipe[aws-parallelcluster-environment::config_default_user_home] + verifier: + controls: + - local_default_user_home + attributes: + cluster: + node_type: 'HeadNode' + scheduler: 'slurm' + default_user_home: 'local' + - name: default_user_local_home_compute + run_list: + - recipe[aws-parallelcluster-tests::setup] + - recipe[aws-parallelcluster-environment::config_default_user_home] + verifier: + controls: + - local_default_user_home + attributes: + cluster: + node_type: 'ComputeFleet' + scheduler: 'slurm' + default_user_home: 'local' + - name: default_user_local_home_login + run_list: + - recipe[aws-parallelcluster-tests::setup] + - recipe[aws-parallelcluster-environment::config_default_user_home] + verifier: + controls: + - local_default_user_home + attributes: + cluster: + node_type: 'LoginNode' + scheduler: 'slurm' + default_user_home: 'local' diff --git a/cookbooks/aws-parallelcluster-environment/recipes/init.rb b/cookbooks/aws-parallelcluster-environment/recipes/init.rb index 820f12e3df..225ce76fc2 100644 --- a/cookbooks/aws-parallelcluster-environment/recipes/init.rb +++ b/cookbooks/aws-parallelcluster-environment/recipes/init.rb @@ -17,6 +17,9 @@ action :configure end +# move the default user dir out of /home if the config param is set to 'local' +include_recipe "aws-parallelcluster-environment::config_default_user_home" + case node['cluster']['shared_storage_type'] when 'efs' include_recipe "aws-parallelcluster-environment::mount_internal_use_efs" diff --git a/cookbooks/aws-parallelcluster-environment/recipes/init/config_default_user_home.rb b/cookbooks/aws-parallelcluster-environment/recipes/init/config_default_user_home.rb new file mode 100644 index 0000000000..200a96c70c --- /dev/null +++ b/cookbooks/aws-parallelcluster-environment/recipes/init/config_default_user_home.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# +# Copyright:: 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# 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. + +return if node['cluster']['default_user_home'] == 'shared' + +# Backup the cluster user's default home directory +bash "Backup #{node['cluster']['cluster_user_home']}" do + user 'root' + group 'root' + code <<-EOH + set -e + if [ -d /tmp#{node['cluster']['cluster_user_home']} ]; then + echo "/tmp#{node['cluster']['cluster_user_home']} exists!" + exit 1 + else + mkdir -p /tmp#{node['cluster']['cluster_user_home']} + fi + rsync -a #{node['cluster']['cluster_user_home']}/ /tmp#{node['cluster']['cluster_user_home']} + EOH +end + +# move the cluster user's default home directory +bash "Move #{node['cluster']['cluster_user_home']}" do + user 'root' + group 'root' + code <<-EOH + set -e + mkdir -p #{node['cluster']['cluster_user_local_home']} + rsync -a /tmp#{node['cluster']['cluster_user_home']}/ #{node['cluster']['cluster_user_local_home']} + usermod -d #{node['cluster']['cluster_user_local_home']} #{node['cluster']['cluster_user']} + chown -R #{node['cluster']['cluster_user']}: #{node['cluster']['cluster_user_local_home']} + rm -rf /tmp#{node['cluster']['cluster_user_home']} + rm -rf #{node['cluster']['cluster_user_home']} + EOH +end + +node.override['cluster']['cluster_user_home'] = node['cluster']['cluster_user_local_home'] diff --git a/cookbooks/aws-parallelcluster-environment/spec/unit/recipes/config_default_user_home_spec.rb b/cookbooks/aws-parallelcluster-environment/spec/unit/recipes/config_default_user_home_spec.rb new file mode 100644 index 0000000000..da2623c3f6 --- /dev/null +++ b/cookbooks/aws-parallelcluster-environment/spec/unit/recipes/config_default_user_home_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe 'aws-parallelcluster-environment::config_default_user_home' do + for_all_oses do |platform, version| + context "on #{platform}#{version}" do + context 'when local' do + cached(:chef_run) do + runner = runner(platform: platform, version: version) do |node| + node.override['cluster']['default_user_home'] = "local" + node.override['cluster']['cluster_user_home'] = "/home/user" + node.override['cluster']['cluster_user_local_home'] = "/local/home/user" + end + runner.converge(described_recipe) + end + cached(:node) { chef_run.node } + + it 'runs the recipe' do + is_expected.to run_bash("Backup /home/user") + is_expected.to run_bash("Move /home/user") + expect(chef_run.node['cluster']['cluster_user_home']).to eq('/local/home/user') + end + end + context 'when shared' do + cached(:chef_run) do + runner = runner(platform: platform, version: version) do |node| + node.override['cluster']['default_user_home'] = "shared" + node.override['cluster']['cluster_user_home'] = "/home/user" + node.override['cluster']['cluster_user_local_home'] = "/local/home/user" + end + runner.converge(described_recipe) + end + cached(:node) { chef_run.node } + + it 'skips the recipe' do + is_expected.not_to run_bash("Backup /home/user") + is_expected.not_to run_bash("Move /home/user") + expect(chef_run.node['cluster']['cluster_user_home']).to eq('/home/user') + end + end + end + end +end diff --git a/cookbooks/aws-parallelcluster-environment/test/controls/config_default_user_home_spec.rb b/cookbooks/aws-parallelcluster-environment/test/controls/config_default_user_home_spec.rb new file mode 100644 index 0000000000..c33836d37a --- /dev/null +++ b/cookbooks/aws-parallelcluster-environment/test/controls/config_default_user_home_spec.rb @@ -0,0 +1,29 @@ +# Copyright:: 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# 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. + +control 'local_default_user_home' do + title 'Check if the home directory is in a local directory' + + only_if { !os_properties.on_docker? } + + describe directory("/local/home") do + it { should exist } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('mode') { should cmp '0755' } + end + describe directory("#{node['cluster']['cluster_user_local_home']}") do + it { should exist } + its('owner') { should eq "#{node['cluster']['cluster_user']}" } + its('group') { should eq "#{node['cluster']['cluster_user']}" } + its('mode') { should cmp '0700' } + end +end diff --git a/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb b/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb index 42043323cf..58e21c855d 100644 --- a/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb +++ b/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb @@ -12,53 +12,88 @@ # OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and # limitations under the License. +node.override['cluster']['cluster_user_home'] = node['cluster']['cluster_user_local_home'] if node['cluster']['default_user_home'] == 'local' + case node['cluster']['node_type'] when 'HeadNode' # Setup cluster user user node['cluster']['cluster_user'] do manage_home true comment 'AWS ParallelCluster user' - home "/home/#{node['cluster']['cluster_user']}" + home "#{node['cluster']['cluster_user_home']}" shell '/bin/bash' end # Setup SSH auth for cluster user bash "ssh-keygen" do - cwd "/home/#{node['cluster']['cluster_user']}" + cwd "#{node['cluster']['cluster_user_home']}" code <<-KEYGEN set -e su - #{node['cluster']['cluster_user']} -c \"ssh-keygen -q -t ed25519 -f ~/.ssh/id_ed25519 -N ''\" KEYGEN - not_if { ::File.exist?("/home/#{node['cluster']['cluster_user']}/.ssh/id_ed25519") } + not_if { ::File.exist?("#{node['cluster']['cluster_user_home']}/.ssh/id_ed25519") } end bash "copy_and_perms" do - cwd "/home/#{node['cluster']['cluster_user']}" + cwd "#{node['cluster']['cluster_user_home']}" code <<-PERMS set -e su - #{node['cluster']['cluster_user']} -c \"cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys && chmod 0600 ~/.ssh/authorized_keys && touch ~/.ssh/authorized_keys_cluster\" PERMS - not_if { ::File.exist?("/home/#{node['cluster']['cluster_user']}/.ssh/authorized_keys_cluster") } + not_if { ::File.exist?("#{node['cluster']['cluster_user_home']}/.ssh/authorized_keys_cluster") } + end + + bash "share_auth_keys_for_local_default_user_home" do + code <<-PERMS + set -e + cp -p #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys #{node['cluster']['shared_dir']} + cp -p #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys #{node['cluster']['shared_dir_login_nodes']} + PERMS + only_if { node['cluster']['default_user_home'] == 'local' } end bash "ssh-keyscan" do - cwd "/home/#{node['cluster']['cluster_user']}" + cwd "#{node['cluster']['cluster_user_home']}" code <<-KEYSCAN set -e su - #{node['cluster']['cluster_user']} -c \"ssh-keyscan #{node['hostname']} > ~/.ssh/known_hosts && chmod 0600 ~/.ssh/known_hosts\" KEYSCAN - not_if { ::File.exist?("/home/#{node['cluster']['cluster_user']}/.ssh/known_hosts") } + not_if { ::File.exist?("#{node['cluster']['cluster_user_home']}/.ssh/known_hosts") } + end + +when 'ComputeFleet' + # Setup cluster user + user node['cluster']['cluster_user'] do + manage_home false + comment 'AWS ParallelCluster user' + home "#{node['cluster']['cluster_user_home']}" + shell '/bin/bash' end -when 'ComputeFleet', 'LoginNode' + bash "copy_auth_file" do + code <<-PERMS + set -e + cp -p #{node['cluster']['shared_dir']}/authorized_keys #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys + PERMS + only_if { node['cluster']['default_user_home'] == 'local' } + end +when 'LoginNode' # Setup cluster user user node['cluster']['cluster_user'] do manage_home false comment 'AWS ParallelCluster user' - home "/home/#{node['cluster']['cluster_user']}" + home "#{node['cluster']['cluster_user_home']}" shell '/bin/bash' end + + bash "copy_auth_file" do + code <<-PERMS + set -e + cp -p #{node['cluster']['shared_dir_login_nodes']}/authorized_keys #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys + PERMS + only_if { node['cluster']['default_user_home'] == 'local' } + end else raise "node_type must be HeadNode, LoginNode or ComputeFleet" end diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users.rb b/cookbooks/aws-parallelcluster-shared/attributes/users.rb index 79f0c7a48a..aec18b5aa4 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users.rb @@ -18,3 +18,6 @@ default['cluster']['munge']['user_id'] = node['cluster']['reserved_base_uid'] + 2 default['cluster']['munge']['group'] = node['cluster']['munge']['user'] default['cluster']['munge']['group_id'] = node['cluster']['munge']['user_id'] + +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb index c3e2344c89..4e329a2153 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb @@ -1,3 +1,5 @@ return unless platform?('amazon') && node['platform_version'] == "2" default['cluster']['cluster_user'] = 'ec2-user' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb index d3e9442567..1577b16509 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb @@ -1,3 +1,5 @@ return unless platform?('centos') && node['platform_version'].to_i == 7 default['cluster']['cluster_user'] = 'centos' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb index e74551dbde..bdd4fc475e 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb @@ -1,3 +1,5 @@ return unless platform?('redhat') && node['platform_version'].to_i == 8 default['cluster']['cluster_user'] = 'ec2-user' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb index 7d5dbbb588..5f4369b2ee 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb @@ -1,3 +1,5 @@ return unless platform?('rocky') && node['platform_version'].to_i == 8 default['cluster']['cluster_user'] = 'rocky' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb index 9ae757f762..690381ed10 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb @@ -1,3 +1,5 @@ return unless platform?('ubuntu') default['cluster']['cluster_user'] = 'ubuntu' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/kitchen.validate-config.yml b/kitchen.validate-config.yml index 4e13ae3873..4fe9458392 100644 --- a/kitchen.validate-config.yml +++ b/kitchen.validate-config.yml @@ -27,6 +27,7 @@ _common_cluster_attributes: &_common_cluster_attributes nvidia: enabled: <%= ENV['NVIDIA_ENABLED'] %> shared_storage_type: ebs + default_user_home: shared _head_node_cluster_attributes: &_head_node_cluster_attributes << : *_common_cluster_attributes