Skip to content

Fix bootstrapping python::pyvenv when Python is not installed #716

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

Merged
merged 2 commits into from
Apr 28, 2025
Merged
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
7 changes: 7 additions & 0 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class { 'python' :

The following parameters are available in the `python` class:

* [`default_system_version`](#-python--default_system_version)
* [`ensure`](#-python--ensure)
* [`version`](#-python--version)
* [`pip`](#-python--pip)
Expand All @@ -92,6 +93,12 @@ The following parameters are available in the `python` class:
* [`anaconda_installer_url`](#-python--anaconda_installer_url)
* [`anaconda_install_path`](#-python--anaconda_install_path)

##### <a name="-python--default_system_version"></a>`default_system_version`

Data type: `Python::Version`

The default version of Python provided by the operating system. Only used as a fallback if Python is not installed yet to determine how to handle some actions that vary depending on the Python version used.

##### <a name="-python--ensure"></a>`ensure`

Data type: `Python::Package::Ensure`
Expand Down
1 change: 1 addition & 0 deletions data/common.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.11"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the common file, the choice of 3.11 was arbitrary. We really only want a default for systems missing in Hiera data (e.g. operating systems not listed as supported). For example the test suite mocks Debian 6, and we do not want to add support for this in Hiera 🙃

1 change: 1 addition & 0 deletions data/os/Archlinux.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.13"
1 change: 1 addition & 0 deletions data/os/Debian/11.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.9"
1 change: 1 addition & 0 deletions data/os/Debian/12.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.11"
1 change: 1 addition & 0 deletions data/os/FreeBSD.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.11"
1 change: 1 addition & 0 deletions data/os/Gentoo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.12"
1 change: 1 addition & 0 deletions data/os/RedHat/8.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.6"
1 change: 1 addition & 0 deletions data/os/RedHat/9.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.9"
1 change: 1 addition & 0 deletions data/os/Ubuntu/20.04.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.8"
1 change: 1 addition & 0 deletions data/os/Ubuntu/22.04.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.10"
1 change: 1 addition & 0 deletions data/os/Ubuntu/24.04.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python::default_system_version: "3.12"
23 changes: 23 additions & 0 deletions hiera.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
version: 5

defaults: # Used for any hierarchy level that omits these keys.
datadir: data # This path is relative to hiera.yaml's directory.
data_hash: yaml_data # Use the built-in YAML backend.

hierarchy:
- name: "archicture"
paths:
- "architecture/%{facts.os.architecture}.yaml"
- "architecture/common.yaml"
- name: "osfamily/major release"
paths:
- "os/%{facts.os.name}/%{facts.os.release.major}.yaml" # Used to distinguish between Debian and Ubuntu
- "os/%{facts.os.family}/%{facts.os.release.major}.yaml" #
- "os/%{facts.os.family}/%{facts.kernelrelease}.yaml" # Used for Solaris
- name: "osfamily"
paths:
- "os/%{facts.os.name}.yaml"
- "os/%{facts.os.family}.yaml"
- name: 'common'
path: 'common.yaml'
2 changes: 2 additions & 0 deletions manifests/init.pp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# @summary Installs and manages python, python-dev and gunicorn.
#
# @param default_system_version The default version of Python provided by the operating system. Only used as a fallback if Python is not installed yet to determine how to handle some actions that vary depending on the Python version used.
# @param ensure Desired installation state for the Python package.
# @param version Python version to install. Beware that valid values for this differ a) by the provider you choose and b) by the osfamily/operatingsystem you are using.
# Allowed values:
Expand Down Expand Up @@ -38,6 +39,7 @@
# }
#
class python (
Python::Version $default_system_version,
Python::Package::Ensure $ensure = 'present',
Python::Version $version = $facts['os']['family'] ? { 'Archlinux' => 'system', default => '3' },
Python::Package::Ensure $pip = 'present',
Expand Down
2 changes: 1 addition & 1 deletion manifests/pyvenv.pp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

if $ensure == 'present' {
$python_version = $version ? {
'system' => $facts['python3_version'],
'system' => $facts['python3_version'].lest || { $python::default_system_version },
default => $version,
}

Expand Down
125 changes: 68 additions & 57 deletions spec/defines/pyvenv_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,83 +6,94 @@
on_supported_os.each do |os, facts|
next if os == 'gentoo-3-x86_64'

let :title do
'/opt/env'
end

context "on #{os}" do
let :facts do
# python3 is required to use pyvenv
facts.merge(
python3_version: '3.5.1'
)
end
let :title do
'/opt/env'
context 'with default parameters' do
let :facts do
facts
end

it { is_expected.to compile }
end

context 'with default parameters' do
it { is_expected.to contain_file('/opt/env').that_requires('Class[python::install]') }
it { is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('pyvenv-3.5 --clear /opt/env && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade pip && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade setuptools') }
context 'with a specific python3 version' do
let :facts do
# python3 is required to use pyvenv
facts.merge(
python3_version: '3.5.1'
)
end

context 'with default parameters' do
it { is_expected.to contain_file('/opt/env').that_requires('Class[python::install]') }
it { is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('pyvenv-3.5 --clear /opt/env && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade pip && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade setuptools') }
end

describe 'when ensure' do
context 'is absent' do
let :params do
{
ensure: 'absent'
}
end

it {
expect(subject).to contain_file('/opt/env').with_ensure('absent').with_purge(true)
}
end
end
end

describe 'when ensure' do
context 'is absent' do
context "prompt on #{os} with python 3.6" do
let :facts do
# python 3.6 is required for venv and prompt
facts.merge(
python3_version: '3.6.1'
)
end
let :title do
'/opt/env'
end

context 'with prompt' do
let :params do
{
ensure: 'absent'
prompt: 'custom prompt',
}
end

it {
expect(subject).to contain_file('/opt/env').with_ensure('absent').with_purge(true)
is_expected.to contain_file('/opt/env').that_requires('Class[python::install]')
is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('python3.6 -m venv --clear --prompt custom\\ prompt /opt/env && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade pip && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade setuptools')
}
end
end
end

context "prompt on #{os} with python 3.6" do
let :facts do
# python 3.6 is required for venv and prompt
facts.merge(
python3_version: '3.6.1'
)
end
let :title do
'/opt/env'
end

context 'with prompt' do
let :params do
{
prompt: 'custom prompt',
}
context "prompt on #{os} with python 3.5" do
let :facts do
facts.merge(
python3_version: '3.5.1'
)
end
let :title do
'/opt/env'
end

it {
is_expected.to contain_file('/opt/env').that_requires('Class[python::install]')
is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('python3.6 -m venv --clear --prompt custom\\ prompt /opt/env && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade pip && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade setuptools')
}
end
end

context "prompt on #{os} with python 3.5" do
let :facts do
facts.merge(
python3_version: '3.5.1'
)
end
let :title do
'/opt/env'
end
context 'with prompt' do
let :params do
{
prompt: 'custom prompt',
}
end

context 'with prompt' do
let :params do
{
prompt: 'custom prompt',
it {
is_expected.to contain_file('/opt/env').that_requires('Class[python::install]')
is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('pyvenv-3.5 --clear /opt/env && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade pip && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade setuptools')
}
end

it {
is_expected.to contain_file('/opt/env').that_requires('Class[python::install]')
is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('pyvenv-3.5 --clear /opt/env && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade pip && /opt/env/bin/pip --log /opt/env/pip.log install --upgrade setuptools')
}
end
end
end
Expand Down
Loading