cookbooks/aws-parallelcluster-platform/spec/unit/resources/dcv_spec.rb (877 lines of code) (raw):
require 'spec_helper'
class ConvergeDcv
def self.setup(chef_run)
chef_run.converge_dsl('aws-parallelcluster-platform') do
dcv 'setup' do
action :setup
end
end
end
def self.configure(chef_run)
chef_run.converge_dsl('aws-parallelcluster-platform') do
dcv 'configure' do
action :configure
end
end
end
def self.nothing(chef_run)
chef_run.converge_dsl('aws-parallelcluster-platform') do
dcv 'nothing' do
action :nothing
end
end
end
end
describe 'dcv:dcv_supported?' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:chef_run) do
runner(platform: platform, version: version, step_into: ['dcv'])
end
cached(:resource) do
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
context 'when on arm' do
before do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(true)
end
case "#{platform}#{version}"
when "amazon2023"
it "is false" do
expect(resource.dcv_supported?).to eq(false)
end
else
it "is true" do
expect(resource.dcv_supported?).to eq(true)
end
end
it 'executes nothing action of dcv resource' do
is_expected.to nothing_dcv('nothing')
end
end
context 'when not on arm' do
is_supported = !("#{platform}#{version}" == 'amazon2023')
it "is #{is_supported}" do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
expect(resource.dcv_supported?).to eq(is_supported)
end
end
end
end
end
describe 'dcv:dcv_*_arch' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:chef_run) do
runner(platform: platform, version: version, step_into: ['dcv'])
end
cached(:resource) do
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
context 'when on arm' do
before do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(true)
end
it 'returns arm architecture' do
expect(resource.dcv_pkg_arch).to eq('arm64')
expect(resource.dcv_url_arch).to eq('aarch64')
end
end
context 'when not on arm' do
before do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
end
it "returns x86_64" do
expect(resource.dcv_pkg_arch).to eq('amd64')
expect(resource.dcv_url_arch).to eq('x86_64')
end
end
end
end
end
describe 'dcv:packages' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:dcv_version) { 'dcv_version-patch' }
cached(:dcv_server_version) { 'dcv_server_version' }
cached(:dcv_webviewer_version) { 'dcv_webviewer_version' }
cached(:dcv_gl_version) { 'dcv_gl_version' }
cached(:xdcv_version) { 'xdcv_version' }
cached(:dcv_url_arch) { 'url_arch' }
cached(:dcv_pkg_arch) { 'pkg_arch' }
cached(:base_os) { 'base_os' }
cached(:chef_run) do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
end
runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node.override['cluster']['dcv']['version'] = dcv_version
node.override['cluster']['dcv']['server']['version'] = dcv_server_version
node.override['cluster']['dcv']['xdcv']['version'] = xdcv_version
node.override['cluster']['dcv']['web_viewer']['version'] = dcv_webviewer_version
node.override['cluster']['dcv']['gl']['version'] = dcv_gl_version
node.override['cluster']['base_os'] = base_os
end
end
cached(:resource) do
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
it 'sets dcv packages' do
if platform == 'ubuntu'
expect(resource.dcv_package).to eq("nice-dcv-#{dcv_version}-#{base_os}-#{dcv_url_arch}")
expect(resource.dcv_server).to eq("nice-dcv-server_#{dcv_server_version}_#{dcv_pkg_arch}.#{base_os}.deb")
expect(resource.xdcv).to eq("nice-xdcv_#{xdcv_version}_#{dcv_pkg_arch}.#{base_os}.deb")
expect(resource.dcv_web_viewer).to eq("nice-dcv-web-viewer_#{dcv_webviewer_version}_#{dcv_pkg_arch}.#{base_os}.deb")
expect(resource.dcv_gl).to eq("/nice-dcv-gl_#{dcv_gl_version}_#{dcv_pkg_arch}.#{base_os}.deb")
elsif "#{platform}#{version}" != 'amazon2023'
dcv_platform_version = "#{platform}#{version}" == "amazon2" ? "7" : version.to_i
dcv_platform_version_pkg = platform == "amazon" ? "amzn2" : "el" + version
expect(resource.dcv_package).to eq("nice-dcv-#{dcv_version}-#{dcv_platform_version_pkg}-#{dcv_url_arch}")
expect(resource.dcv_server).to eq("nice-dcv-server-#{dcv_server_version}.el#{dcv_platform_version}.#{dcv_url_arch}.rpm")
expect(resource.xdcv).to eq("nice-xdcv-#{xdcv_version}.el#{dcv_platform_version}.#{dcv_url_arch}.rpm")
expect(resource.dcv_web_viewer).to eq("nice-dcv-web-viewer-#{dcv_webviewer_version}.el#{dcv_platform_version}.#{dcv_url_arch}.rpm")
expect(resource.dcv_gl).to eq("nice-dcv-gl-#{dcv_gl_version}.el#{dcv_platform_version}.#{dcv_url_arch}.rpm")
end
end
end
end
end
describe 'dcv:dcv_gpu_accel_supported?' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:chef_run) do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
runner(platform: platform, version: version, step_into: ['dcv'])
end
cached(:node) { chef_run.node }
cached(:resource) do
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
context 'when not graphic instance' do
before do
allow_any_instance_of(Object).to receive(:graphic_instance?).and_return(false)
end
it 'returns false' do
expect(resource.dcv_gpu_accel_supported?).to eq(false)
end
end
context 'when graphic instance' do
before do
allow_any_instance_of(Object).to receive(:graphic_instance?).and_return(true)
end
context 'and nvidia not installed' do
before do
allow_any_instance_of(Object).to receive(:nvidia_installed?).and_return(false)
end
it 'returns false' do
expect(resource.dcv_gpu_accel_supported?).to eq(false)
end
end
context 'and nvidia installed' do
before do
allow_any_instance_of(Object).to receive(:nvidia_installed?).and_return(true)
end
context('and instance type is g5g') do
before { node.override['ec2']['instance_type'] = 'g5g.any' }
it 'returns false' do
expect(resource.dcv_gpu_accel_supported?).to eq(false)
end
end
context('and instance type is not g5g') do
before { node.override['ec2']['instance_type'] = 'c5c.any' }
it 'returns true' do
expect(resource.dcv_gpu_accel_supported?).to eq(true)
end
end
end
end
end
end
end
describe 'dcv:dcv_url' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:dcv_major_minor) { 'major.minor' }
cached(:dcv_version) { "#{dcv_major_minor}-patch" }
cached(:dcv_package) { "dcv_package" }
cached(:chef_run) do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node.override['cluster']['dcv']['version'] = dcv_version
end
end
cached(:node) { chef_run.node }
cached(:resource) do
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_package).and_return(dcv_package)
end
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
it 'returns dcv_url' do
expect(resource.dcv_url).to eq("#{node['cluster']['artifacts_s3_url']}/dependencies/dcv/#{dcv_package}.tgz")
end
end
end
end
describe 'dcv:dcv_tarball' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:sources_dir) { 'sources_dir' }
cached(:dcv_version) { "dcv_version" }
cached(:chef_run) do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node.override['cluster']['sources_dir'] = sources_dir
node.override['cluster']['dcv']['version'] = dcv_version
end
end
cached(:node) { chef_run.node }
cached(:resource) do
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
it 'returns dcv_tarball' do
expect(resource.dcv_tarball).to eq("#{sources_dir}/dcv-#{dcv_version}.tgz")
end
end
end
end
describe 'dcv:dcvauth_virtualenv' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:system_pyenv_root) { 'system_pyenv_root' }
cached(:python_version) { "python_version" }
cached(:virtualenv) { 'dcv_authenticator_virtualenv' }
cached(:chef_run) do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node.override['cluster']['system_pyenv_root'] = system_pyenv_root
node.override['cluster']['python-version'] = python_version
end
end
cached(:node) { chef_run.node }
cached(:resource) do
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
it 'sets dcvauth virtualenv' do
expect(resource.dcvauth_virtualenv).to eq(virtualenv)
expect(resource.dcvauth_virtualenv_path).to eq("#{node['cluster']['system_pyenv_root']}/versions/#{python_version}/envs/#{virtualenv}")
end
end
end
end
describe 'dcv:prereq_packages on amazon linux' do
cached(:chef_run) do
runner(platform: 'amazon', version: '2', step_into: ['dcv'])
end
cached(:resource) do
ConvergeDcv.nothing(chef_run)
chef_run.find_resource('dcv', 'nothing')
end
cached(:common_prereq_packages) do
%w(gdm gnome-session gnome-classic-session gnome-session-xsession
xorg-x11-server-Xorg xorg-x11-fonts-Type1 xorg-x11-drivers
gnu-free-fonts-common gnu-free-mono-fonts gnu-free-sans-fonts
gnu-free-serif-fonts glx-utils)
end
context 'when on arm' do
before do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(true)
end
it 'returns prereq package list with mate-terminal' do
expect(resource.prereq_packages).to eq(common_prereq_packages + %w(mate-terminal))
end
end
context 'when not on arm' do
before do
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
end
it 'returns prereq package list with gnome-terminal' do
expect(resource.prereq_packages).to eq(common_prereq_packages + %w(gnome-terminal))
end
end
end
describe 'dcv:setup' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:scripts_dir) { 'scripts_dir' }
cached(:sources_dir) { 'sources_dir' }
cached(:authenticator_group) { 'authenticator_group' }
cached(:authenticator_group_id) { 'authenticator_group_id' }
cached(:authenticator_user) { 'authenticator_user' }
cached(:authenticator_user_id) { 'authenticator_user_id' }
cached(:authenticator_user_home) { 'authenticator_user_home' }
cached(:dcv_version) { 'dcv_version' }
cached(:dcv_server_version) { 'dcv_server_version' }
cached(:dcv_webviewer_version) { 'dcv_webviewer_version' }
cached(:xdcv_version) { 'xdcv_version' }
cached(:dcv_tarball) { 'dcv_tarball' }
cached(:base_os) { 'base_os' }
cached(:checksum) { 'checksum' }
cached(:system_pyenv_root) { 'system_pyenv_root' }
cached(:python_version) { 'python-version' }
cached(:alinux_prereq_packages) { 'alinux_prereq_packages' }
cached(:dcv_url_arch) { 'dcv_url_arch' }
cached(:dcv_pkg_arch) { 'dcv_pkg_arch' }
cached(:dcv_package) { 'dcv_package' }
cached(:dcv_server) { 'dcv_server' }
cached(:xdcv) { 'xdcv' }
cached(:dcv_web_viewer) { 'dcv_web_viewer' }
cached(:dcv_url) { 's3://dcv_url' }
cached(:dcvauth_virtualenv) { 'dcvauth_virtualenv' }
cached(:dcvauth_virtualenv_path) { 'dcvauth_virtualenv_path' }
cached(:node_setup) do
lambda { |node|
node.override['cluster']['sources_dir'] = sources_dir
node.override['cluster']['scripts_dir'] = scripts_dir
node.override['cluster']['dcv']['authenticator']['group'] = authenticator_group
node.override['cluster']['dcv']['authenticator']['group_id'] = authenticator_group_id
node.override['cluster']['dcv']['authenticator']['user'] = authenticator_user
node.override['cluster']['dcv']['authenticator']['user_id'] = authenticator_user_id
node.override['cluster']['dcv']['authenticator']['user_home'] = authenticator_user_home
node.override['cluster']['dcv']['version'] = dcv_version
node.override['cluster']['is_official_ami_build'] = true
node.override['cluster']['system_pyenv_root'] = 'system_pyenv_root'
node.override['cluster']['python-version'] = 'python-version'
}
end
cached(:res_setup) do
lambda { |res|
allow(res).to receive(:dcv_sha256sum).and_return(checksum)
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:prereq_packages).and_return(alinux_prereq_packages) if platform == 'amazon'
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_server).and_return(dcv_server)
allow(res).to receive(:xdcv).and_return(xdcv)
allow(res).to receive(:dcv_web_viewer).and_return(dcv_web_viewer)
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
allow(res).to receive(:dcv_url).and_return(dcv_url)
allow(res).to receive(:dcv_tarball).and_return(dcv_tarball)
allow(res).to receive(:dcvauth_virtualenv).and_return(dcvauth_virtualenv)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
}
end
cached(:method_setup) do
lambda {
stub_command('which getenforce').and_return(true)
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
allow(::File).to receive(:exist?).with('/etc/dcv/dcv.conf').and_return(false)
allow(::File).to receive(:exist?).with(dcv_tarball).and_return(false)
}
end
context "when dcv supported" do
cached(:chef_run) do
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
end
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_sha256sum).and_return(checksum)
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:prereq_packages).and_return(alinux_prereq_packages) if platform == 'amazon'
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_server).and_return(dcv_server)
allow(res).to receive(:xdcv).and_return(xdcv)
allow(res).to receive(:dcv_web_viewer).and_return(dcv_web_viewer)
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
allow(res).to receive(:dcv_url).and_return(dcv_url)
allow(res).to receive(:dcv_tarball).and_return(dcv_tarball)
allow(res).to receive(:dcvauth_virtualenv).and_return(dcvauth_virtualenv)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
end
method_setup.call
ConvergeDcv.setup(runner)
end
cached(:node) { chef_run.node }
it 'sets up dcv' do
is_expected.to setup_dcv('setup')
end
it 'creates directories' do
is_expected.to create_directory(scripts_dir).with_recursive(true)
is_expected.to create_directory(sources_dir).with_recursive(true)
end
it 'installs pcluster_dcv_connect.sh script to use it for error handling' do
is_expected.to create_if_missing_cookbook_file("#{scripts_dir}/pcluster_dcv_connect.sh").with(
source: 'dcv/pcluster_dcv_connect.sh',
owner: 'root',
group: 'root',
mode: '0755'
)
end
it 'sets up dcv authenticator group' do
is_expected.to create_group(authenticator_group).with(
comment: 'Amazon DCV External Authenticator group',
gid: authenticator_group_id,
system: true
)
end
it 'sets up dcv authenticator user' do
is_expected.to create_user(authenticator_user).with(
comment: 'Amazon DCV External Authenticator user',
gid: authenticator_group_id,
uid: authenticator_user_id,
manage_home: true,
home: authenticator_user_home,
system: true,
shell: '/bin/bash'
)
end
it 'installs prerequisites' do
case platform
when 'ubuntu'
is_expected.to periodic_apt_update('')
is_expected.to run_bash('install pre-req').with_cwd(Chef::Config[:file_cache_path]).with_retries(10).with_retry_delay(5)
.with_code(/apt -y install whoopsie/)
.with_code(/apt -y install ubuntu-desktop && apt -y install mesa-utils || (dpkg --configure -a && exit 1)/)
.with_code(/apt -y purge ifupdown/)
.with_code(%r{wget https://d1uj6qtbmh3dt5.cloudfront.net/NICE-GPG-KEY})
when 'amazon'
if version == '2'
is_expected.to install_package(alinux_prereq_packages).with_retries(10).with_retry_delay(5)
is_expected.to create_file('Setup Gnome standard').with(
content: "PREFERRED=/usr/bin/gnome-session",
owner: "root",
group: "root",
mode: "0755",
path: "/etc/sysconfig/desktop"
)
end
else
is_expected.to run_execute('Install gnome desktop').with_command('yum -y install @gnome').with_retries(3).with_retry_delay(5)
is_expected.to install_package('xorg-x11-server-Xorg').with_retries(3).with_retry_delay(5)
is_expected.to disable_service('libvirtd').with_action(%i(disable stop))
end
end
it 'disables lock screen' do
is_expected.to create_cookbook_file('/usr/share/glib-2.0/schemas/10_org.gnome.desktop.screensaver.gschema.override').with(
source: 'dcv/10_org.gnome.desktop.screensaver.gschema.override',
owner: 'root',
group: 'root',
mode: '0755'
)
is_expected.to run_execute('Compile gsettings schema').with_command('glib-compile-schemas /usr/share/glib-2.0/schemas/')
end
it 'downloads DCV packages' do
is_expected.to create_remote_file(dcv_tarball).with(
source: dcv_url,
mode: '0644',
checksum: checksum,
retries: 3,
retry_delay: 5
)
end
it 'extracts DCV packages' do
is_expected.to run_bash('extract dcv packages').with_cwd(sources_dir).with_code("tar -xvzf #{dcv_tarball}")
end
it 'installs server package' do
pkg = "#{sources_dir}/#{dcv_package}/#{dcv_server}"
if platform == 'ubuntu'
is_expected.to run_execute("apt install dcv package #{pkg}").with(
command: "apt -y install #{pkg}",
retries: 3,
retry_delay: 5
)
else
is_expected.to install_package(pkg).with_source(pkg)
end
end
it 'installs xdcv package' do
pkg = "#{sources_dir}/#{dcv_package}/#{xdcv}"
if platform == 'ubuntu'
is_expected.to run_execute("apt install dcv package #{pkg}").with(
command: "apt -y install #{pkg}",
retries: 3,
retry_delay: 5
)
else
is_expected.to install_package(pkg).with_source(pkg)
end
end
it 'installs xdcv package' do
pkg = "#{sources_dir}/#{dcv_package}/#{dcv_web_viewer}"
if platform == 'ubuntu'
is_expected.to run_execute("apt install dcv package #{pkg}").with(
command: "apt -y install #{pkg}",
retries: 3,
retry_delay: 5
)
else
is_expected.to install_package(pkg).with_source(pkg)
end
end
it 'activates python virtual env' do
is_expected.to run_install_pyenv('pyenv for default python version')
is_expected.to run_activate_virtual_env(dcvauth_virtualenv).with(
pyenv_path: dcvauth_virtualenv_path,
python_version: python_version
)
end
it 'executes postinstall operations' do
case platform
when 'redhat', 'centos'
# stop firewall
is_expected.to disable_service('firewalld').with_action(%i(disable stop))
# Disable selinux
is_expected.to disabled_selinux_state('SELinux Disabled')
end
end
it 'switches runlevel to multi-user.target for official ami' do
is_expected.to run_execute('set default systemd runlevel to multi-user.target').with_command('systemctl set-default multi-user.target')
end
end
context "when dcv not supported" do
cached(:chef_run) do
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
end
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_sha256sum).and_return(checksum)
allow(res).to receive(:dcv_supported?).and_return(false)
allow(res).to receive(:prereq_packages).and_return(alinux_prereq_packages) if platform == 'amazon'
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_server).and_return(dcv_server)
allow(res).to receive(:xdcv).and_return(xdcv)
allow(res).to receive(:dcv_web_viewer).and_return(dcv_web_viewer)
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
allow(res).to receive(:dcv_url).and_return(dcv_url)
allow(res).to receive(:dcv_tarball).and_return(dcv_tarball)
allow(res).to receive(:dcvauth_virtualenv).and_return(dcvauth_virtualenv)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
end
method_setup.call
ConvergeDcv.setup(runner)
end
it 'dcv not supported' do
expect(chef_run.find_resource('dcv', 'setup').dcv_supported?).to eq(false)
end
it 'installs pcluster_dcv_connect.sh script to use it for error handling' do
is_expected.to create_if_missing_cookbook_file("#{scripts_dir}/pcluster_dcv_connect.sh")
end
it 'does not set up dcv' do
is_expected.not_to create_group(authenticator_group)
is_expected.not_to create_user(authenticator_user)
end
it 'switches runlevel to multi-user.target for official ami' do
is_expected.to run_execute('set default systemd runlevel to multi-user.target').with_command('systemctl set-default multi-user.target')
end
end
context "when dcv already installed" do
cached(:chef_run) do
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
end
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_sha256sum).and_return(checksum)
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:prereq_packages).and_return(alinux_prereq_packages) if platform == 'amazon'
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_server).and_return(dcv_server)
allow(res).to receive(:xdcv).and_return(xdcv)
allow(res).to receive(:dcv_web_viewer).and_return(dcv_web_viewer)
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
allow(res).to receive(:dcv_url).and_return(dcv_url)
allow(res).to receive(:dcv_tarball).and_return(dcv_tarball)
allow(res).to receive(:dcvauth_virtualenv).and_return(dcvauth_virtualenv)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
end
method_setup.call
allow(::File).to receive(:exist?).with('/etc/dcv/dcv.conf').and_return(true)
ConvergeDcv.setup(runner)
end
it 'does not install dcv' do
is_expected.not_to create_if_missing_cookbook_file("#{scripts_dir}/pcluster_dcv_connect.sh")
is_expected.not_to create_group(authenticator_group)
is_expected.not_to create_user(authenticator_user)
is_expected.not_to run_execute('set default systemd runlevel to multi-user.target')
end
end
context "when not official ami build" do
cached(:chef_run) do
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
node.override['cluster']['is_official_ami_build'] = false
end
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_sha256sum).and_return(checksum)
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:prereq_packages).and_return(alinux_prereq_packages) if platform == 'amazon'
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_server).and_return(dcv_server)
allow(res).to receive(:xdcv).and_return(xdcv)
allow(res).to receive(:dcv_web_viewer).and_return(dcv_web_viewer)
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
allow(res).to receive(:dcv_url).and_return(dcv_url)
allow(res).to receive(:dcv_tarball).and_return(dcv_tarball)
allow(res).to receive(:dcvauth_virtualenv).and_return(dcvauth_virtualenv)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
end
method_setup.call
ConvergeDcv.setup(runner)
end
it 'does not switch runlevel to multi-user.target' do
is_expected.not_to run_execute('set default systemd runlevel to multi-user.target')
end
end
context "when dcv tarball exists" do
cached(:chef_run) do
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
node.override['cluster']['is_official_ami_build'] = false
end
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_sha256sum).and_return(checksum)
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:prereq_packages).and_return(alinux_prereq_packages) if platform == 'amazon'
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_server).and_return(dcv_server)
allow(res).to receive(:xdcv).and_return(xdcv)
allow(res).to receive(:dcv_web_viewer).and_return(dcv_web_viewer)
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
allow(res).to receive(:dcv_url).and_return(dcv_url)
allow(res).to receive(:dcv_tarball).and_return(dcv_tarball)
allow(res).to receive(:dcvauth_virtualenv).and_return(dcvauth_virtualenv)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
end
method_setup.call
allow(::File).to receive(:exist?).with(dcv_tarball).and_return(true)
ConvergeDcv.setup(runner)
end
it 'does not download and install DCV packages' do
is_expected.not_to create_remote_file(dcv_tarball)
is_expected.not_to run_bash('extract dcv packages').with_cwd(sources_dir).with_code("tar -xvzf #{dcv_tarball}")
end
end
context "when virtual env already activated" do
cached(:chef_run) do
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_sha256sum).and_return(checksum)
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:prereq_packages).and_return(alinux_prereq_packages) if platform == 'amazon'
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_server).and_return(dcv_server)
allow(res).to receive(:xdcv).and_return(xdcv)
allow(res).to receive(:dcv_web_viewer).and_return(dcv_web_viewer)
allow(res).to receive(:dcv_url_arch).and_return(dcv_url_arch)
allow(res).to receive(:dcv_pkg_arch).and_return(dcv_pkg_arch)
allow(res).to receive(:dcv_url).and_return(dcv_url)
allow(res).to receive(:dcv_tarball).and_return(dcv_tarball)
allow(res).to receive(:dcvauth_virtualenv).and_return(dcvauth_virtualenv)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
end
method_setup.call
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
end
allow(::File).to receive(:exist?).with("#{dcvauth_virtualenv_path}/bin/activate").and_return(true)
ConvergeDcv.setup(runner)
end
it 'does not activate dcv authenticator virtual env' do
is_expected.not_to run_install_pyenv('pyenv for default python version')
is_expected.not_to run_activate_virtual_env(dcvauth_virtualenv)
end
end
end
end
end
describe 'dcv:configure' do
for_all_oses do |platform, version|
context "on #{platform}#{version}" do
cached(:sources_dir) { 'sources_dir' }
cached(:dcv_version) { 'dcv_version' }
cached(:dcv_gl_version) { 'dcv_gl_version' }
cached(:dcv_pkg_arch) { 'amd64' }
cached(:dcv_url_arch) { 'x86_64' }
cached(:base_os) { 'base_os' }
cached(:certificate) { 'certificate' }
cached(:private_key) { 'private_key' }
cached(:user) { 'user' }
cached(:user_home) { 'user_home' }
cached(:dcv_package) { 'dcv_package' }
cached(:dcv_gl) { 'dcv_gl' }
cached(:dcvauth_virtualenv_path) { 'dcvauth_virtualenv_path' }
cached(:node_setup) do
lambda { |node|
node.override['ec2']['instance_type'] = 'any'
node.override['cluster']['sources_dir'] = sources_dir
node.override['cluster']['node_type'] = 'HeadNode'
node.override['cluster']['dcv']['gl']['version'] = dcv_gl_version
node.override['cluster']['base_os'] = base_os
node.override['cluster']['dcv']['version'] = dcv_version
node.override['cluster']['dcv']['gl']['version'] = dcv_gl_version
node.override['cluster']['dcv']['authenticator']['certificate'] = certificate
node.override['cluster']['dcv']['authenticator']['private_key'] = private_key
node.override['cluster']['dcv']['authenticator']['user'] = user
node.override['cluster']['dcv']['authenticator']['user_home'] = user_home
node.override['cluster']['dcv']['authenticator']['virtualenv_path'] = dcvauth_virtualenv_path
}
end
context "when dcv_gpu_accel_supported" do
cached(:chef_run) do
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:dcv_gpu_accel_supported?).and_return(true)
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_gl).and_return(dcv_gl)
allow(res).to receive(:dcvauth_virtualenv_path).and_return(dcvauth_virtualenv_path)
end
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
end
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
allow_any_instance_of(Object).to receive(:graphic_instance?).and_return(true)
allow_any_instance_of(Object).to receive(:nvidia_installed?).and_return(true)
ConvergeDcv.configure(runner)
end
cached(:node) { chef_run.node }
it 'configures dcv' do
is_expected.to configure_dcv('configure')
end
it 'sets up Nvidia drivers for X configuration' do
is_expected.to run_execute('Set up Nvidia drivers for X configuration')
.with_user('root')
.with_command('nvidia-xconfig --preserve-busid --enable-all-gpus')
end
it 'installs DCV gl' do
if platform == 'ubuntu'
is_expected.to run_execute('apt install dcv-gl')
.with_command("apt -y install #{sources_dir}/#{dcv_package}/#{dcv_gl}")
else
is_expected.to install_package("#{sources_dir}/#{dcv_package}/#{dcv_gl}")
.with_source("#{sources_dir}/#{dcv_package}/#{dcv_gl}")
end
end
# Configure the X server to start automatically when the Linux server boots and start the X server in background
it 'configures the X server to start automatically when the Linux server boots and start the X server in background' do
is_expected.to run_bash('Launch X').with_user('root')
.with_code(/systemctl set-default graphical.target/)
.with_code(/systemctl isolate graphical.target &/)
end
it 'verifies that the X server is running' do
is_expected.to run_execute('Wait for X to start').with(
user: 'root',
command: "pidof X || pidof Xorg",
retries: 10,
retry_delay: 5
)
end
if platform == 'ubuntu'
it 'disables RNDFILE from openssl to avoid error during certificate generation' do
is_expected.to run_execute('No RND')
.with_user('root')
.with_command("sed --in-place '/RANDFILE/d' /etc/ssl/openssl.cnf")
end
end
it 'installs utility file to generate HTTPs certificates for the DCV external authenticator and generate a new one' do
is_expected.to create_cookbook_file('/etc/parallelcluster/generate_certificate.sh').with(
source: 'dcv/generate_certificate.sh',
owner: 'root',
mode: '0700'
)
is_expected.to run_execute('certificate generation')
.with_user('root')
.with_command("/etc/parallelcluster/generate_certificate.sh \"#{certificate}\" \"#{private_key}\" #{user} dcv")
end
it 'generates dcv.conf' do
is_expected.to create_template('/etc/dcv/dcv.conf').with(
source: 'dcv/dcv.conf.erb',
owner: 'root',
group: 'root',
mode: '0755'
)
end
it 'creates directory for the external authenticator to store access file created by the users' do
is_expected.to create_directory('/var/spool/parallelcluster/pcluster_dcv_authenticator').with(
owner: user,
mode: '1733',
recursive: true
)
end
it 'installs DCV external authenticator' do
is_expected.to create_cookbook_file("#{user_home}/pcluster_dcv_authenticator.py").with(
source: 'dcv/pcluster_dcv_authenticator.py',
owner: user,
mode: '0700'
)
end
it 'starts Amazon DCV server' do
is_expected.to enable_service('dcvserver').with_action(%i(enable start))
end
end
context "when g2 instance" do
cached(:chef_run) do
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:dcv_gpu_accel_supported?).and_return(true)
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_gl).and_return(dcv_gl)
end
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node_setup.call(node)
node.override['ec2']['instance_type'] = 'g2.any'
end
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
allow_any_instance_of(Object).to receive(:graphic_instance?).and_return(true)
allow_any_instance_of(Object).to receive(:nvidia_installed?).and_return(true)
ConvergeDcv.configure(runner)
end
cached(:node) { chef_run.node }
it 'sets up Nvidia drivers for X configuration' do
is_expected.to run_execute('Set up Nvidia drivers for X configuration')
.with_user('root')
.with_command('nvidia-xconfig --preserve-busid --enable-all-gpus --use-display-device=none')
end
end
context "when dcv_gpu_accel not supported" do
cached(:chef_run) do
stubs_for_resource('dcv') do |res|
allow(res).to receive(:dcv_supported?).and_return(true)
allow(res).to receive(:dcv_gpu_accel_supported?).and_return(false)
allow(res).to receive(:dcv_package).and_return(dcv_package)
allow(res).to receive(:dcv_gl).and_return(dcv_gl)
end
runner = runner(platform: platform, version: version, step_into: ['dcv']) do |node|
node.override['ec2']['instance_type'] = 'any'
node.override['cluster']['sources_dir'] = sources_dir
node.override['cluster']['node_type'] = 'HeadNode'
node.override['cluster']['dcv']['gl']['version'] = dcv_gl_version
node.override['cluster']['base_os'] = base_os
node.override['cluster']['dcv']['version'] = dcv_version
node.override['cluster']['dcv']['gl']['version'] = dcv_gl_version
node.override['cluster']['dcv']['authenticator']['certificate'] = certificate
node.override['cluster']['dcv']['authenticator']['private_key'] = private_key
node.override['cluster']['dcv']['authenticator']['user'] = user
node.override['cluster']['dcv']['authenticator']['user_home'] = user_home
end
allow_any_instance_of(Object).to receive(:arm_instance?).and_return(false)
allow_any_instance_of(Object).to receive(:graphic_instance?).and_return(true)
allow_any_instance_of(Object).to receive(:nvidia_installed?).and_return(true)
ConvergeDcv.configure(runner)
end
cached(:node) { chef_run.node }
it 'does not install DCV gl' do
if platform == 'ubuntu'
is_expected.not_to run_execute('apt install dcv-gl')
else
is_expected.not_to install_package("#{sources_dir}/#{dcv_package}/#{dcv_gl}")
end
end
it 'sets default systemd runlevel to graphical.target' do
is_expected.to run_bash('set default systemd runlevel to graphical.target')
.with_user('root')
.with_code(/systemctl set-default graphical.target/)
.with_code(/systemctl isolate graphical.target &/)
end
end
end
end
end