require 'spec_helper' # parallelcluster default source dir defined in attributes source_dir = '/opt/parallelcluster/sources' efa_version = '1.24.0' efa_checksum = '878623f819a0d9099d76ecd41cf4f569d4c3aac0c9bb7ba9536347c50b6bf88e' class ConvergeEfa def self.setup(chef_run) chef_run.converge_dsl('aws-parallelcluster-environment') do efa 'setup' do action :setup end end end # Converge efa:configure def self.configure(chef_run) chef_run.converge_dsl('aws-parallelcluster-environment') do efa 'configure' do action :configure end end end end describe 'efa:setup' do for_all_oses do |platform, version| context "on #{platform}#{version}" do cached(:prerequisites) do if platform == 'redhat' %w(environment-modules libibverbs-utils librdmacm-utils rdma-core-devel) elsif platform == 'amazon' %w(environment-modules libibverbs-utils librdmacm-utils) else "environment-modules" end end let(:chef_run) do runner(platform: platform, version: version, step_into: ['efa']) do |node| if platform == 'redhat'; node.automatic['platform_version'] = "8.7" end end end context 'when efa installed' do before do stubs_for_provider('efa') do |resource| allow(resource).to receive(:efa_installed?).and_return(true) end end context 'and installer tarball does not exist' do before do mock_file_exists("#{source_dir}/aws-efa-installer.tar.gz", false) ConvergeEfa.setup(chef_run) end it 'exits with warning' do is_expected.to write_log('efa installed') .with(message: 'Existing EFA version differs from the one shipped with ParallelCluster. Skipping ParallelCluster EFA installation and configuration.') .with(level: :warn) end end context 'and installer tarball exists' do before do mock_file_exists("#{source_dir}/aws-efa-installer.tar.gz", true) ConvergeEfa.setup(chef_run) end it 'installs EFA' do is_expected.not_to write_log('efa installed') is_expected.not_to remove_package(%w(openmpi-devel openmpi)) is_expected.to update_package_repos('update package repos') is_expected.to install_package(prerequisites) is_expected.to create_if_missing_remote_file("#{source_dir}/aws-efa-installer.tar.gz") is_expected.not_to run_bash('install efa') end end end context 'when efa not installed' do before do stubs_for_provider('efa') do |resource| allow(resource).to receive(:efa_installed?).and_return(false) end end context 'when efa supported' do before do allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false) ConvergeEfa.setup(chef_run) end it 'installs EFA without skipping kmod' do is_expected.to create_directory(source_dir) is_expected.to setup_efa('setup') is_expected.not_to write_log('efa installed') is_expected.to remove_package(platform == 'ubuntu' ? ['libopenmpi-dev'] : %w(openmpi-devel openmpi)) is_expected.to update_package_repos('update package repos') is_expected.to install_package(prerequisites) is_expected.to create_if_missing_remote_file("#{source_dir}/aws-efa-installer.tar.gz") .with(source: "https://efa-installer.amazonaws.com/aws-efa-installer-#{efa_version}.tar.gz") .with(mode: '0644') .with(retries: 3) .with(retry_delay: 5) .with(checksum: efa_checksum) is_expected.to run_bash('install efa') .with(code: %( set -e tar -xzf #{source_dir}/aws-efa-installer.tar.gz cd aws-efa-installer ./efa_installer.sh -y rm -rf #{source_dir}/aws-efa-installer )) end end end end end context 'when rhel version is older than 8.4' do cached(:chef_run) do runner = ChefSpec::Runner.new( # Create a runner for the given platform/version platform: "redhat", step_into: ['efa'] ) do |node| node.automatic['platform_version'] = "8.3" end ConvergeEfa.setup(runner) end it "logs EFA not supported message" do is_expected.to write_log('EFA is not supported in this RHEL version 8.3, supported versions are >= 8.4').with_level(:warn) end it "doesn't install EFA kmod" do is_expected.to run_bash('install efa').with_code(%r{./efa_installer.sh -y -k}) end end context 'when centos on arm' do cached(:chef_run) do runner = ChefSpec::Runner.new( platform: "centos", version: '7', step_into: ['efa'] ) allow_any_instance_of(Object).to receive(:arm_instance?).and_return(true) ConvergeEfa.setup(runner) end it "doesn't install EFA kmod" do is_expected.to run_bash('install efa').with_code(%r{./efa_installer.sh -y -k}) end end end describe 'efa:configure' do for_all_oses do |platform, version| context "on #{platform}#{version}" do let(:chef_run) do runner(platform: platform, version: version, step_into: ['efa']) end if %w(amazon centos redhat).include?(platform) it 'does nothing' do ConvergeEfa.configure(chef_run) is_expected.to configure_efa('configure') is_expected.to write_node_attributes('dump node attributes') is_expected.not_to apply_sysctl('kernel.yama.ptrace_scope') end elsif platform == 'ubuntu' context 'when efa enabled on compute node' do before do chef_run.node.override['cluster']['enable_efa'] = 'efa' chef_run.node.override['cluster']['node_type'] = 'ComputeFleet' ConvergeEfa.configure(chef_run) end it 'disables ptrace protection on compute nodes' do is_expected.to apply_sysctl('kernel.yama.ptrace_scope').with(value: "0") end end context 'when efa not enabled on compute node' do before do chef_run.node.override['cluster']['enable_efa'] = 'other' chef_run.node.override['cluster']['node_type'] = 'ComputeFleet' ConvergeEfa.configure(chef_run) end it 'does not disable ptrace protection' do is_expected.not_to apply_sysctl('kernel.yama.ptrace_scope') end end context 'when it is not a compute node' do before do chef_run.node.override['cluster']['enable_efa'] = 'efa' chef_run.node.override['cluster']['node_type'] = 'other' ConvergeEfa.configure(chef_run) end it 'does not disable ptrace protection' do is_expected.not_to apply_sysctl('kernel.yama.ptrace_scope') end end else pending "Implement for #{platform}" end end end end