Repository navigation
Allow Forge VM runs to disable the default synced folder #963
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: master
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -3,6 +3,10 @@ if ARGV.any? { |arg| %w[up provision reload].include?(arg) } && ENV['ANSIBLE_COL | |
| end | ||
|
|
||
| DOMAIN = ENV.fetch('VAGRANT_DOMAIN', 'example.com'.freeze) | ||
| SYNCED_FOLDER = ENV.fetch('FOREMANCTL_SYNCED_FOLDER', 'enabled') | ||
| unless %w[enabled disabled].include?(SYNCED_FOLDER) | ||
| abort('FOREMANCTL_SYNCED_FOLDER must be enabled or disabled') | ||
| end | ||
|
|
||
| # Official CentOS libvirt images include swap; Vagrant Cloud boxes do not. | ||
| def set_centos_box_url(vm) | ||
|
|
@@ -13,7 +17,7 @@ def set_centos_box_url(vm) | |
| end | ||
|
|
||
| Vagrant.configure("2") do |config| | ||
| config.vm.synced_folder ".", "/vagrant" | ||
| config.vm.synced_folder ".", "/vagrant", disabled: SYNCED_FOLDER == 'disabled' | ||
|
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.
|
||
|
|
||
| config.vm.provision("etc_hosts", type: 'ansible') do |ansible| | ||
| ansible.playbook = "development/playbooks/etc_host.yml" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| import json | ||
| import os | ||
| import shutil | ||
| import subprocess | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def forge_vms(tmp_path): | ||
| root = Path(__file__).resolve().parents[2] | ||
| shutil.copy2(root / 'forge', tmp_path / 'forge') | ||
| shutil.copytree(root / 'development/playbooks/vms', tmp_path / 'development/playbooks/vms') | ||
| inventory = tmp_path / 'inventories' | ||
| inventory.mkdir() | ||
| (inventory / 'localhost').write_text( | ||
| f'localhost ansible_connection=local ansible_python_interpreter={sys.executable}\n' | ||
| ) | ||
| scripts = tmp_path / 'development/scripts' | ||
| scripts.mkdir() | ||
| inventory_script = scripts / 'vagrant.py' | ||
| inventory_script.write_text('#!/bin/sh\nprintf "all:\\n hosts: {}\\n"\n') | ||
| inventory_script.chmod(0o755) | ||
|
|
||
| # Record the Vagrant commands without allocating or changing any VMs. | ||
| binaries = tmp_path / 'bin' | ||
| binaries.mkdir() | ||
| vagrant = binaries / 'vagrant' | ||
| vagrant.write_text( | ||
| f'#!{sys.executable}\n' | ||
| 'import json, os, sys\n' | ||
| 'with open(os.environ["VAGRANT_TEST_LOG"], "a") as log:\n' | ||
| ' log.write(json.dumps([sys.argv[1:], os.environ.get("FOREMANCTL_SYNCED_FOLDER")]) + "\\n")\n' | ||
| ) | ||
| vagrant.chmod(0o755) | ||
| config = tmp_path / 'ansible.cfg' | ||
| config.write_text('[defaults]\nretry_files_enabled = false\n') | ||
| log = tmp_path / 'vagrant.jsonl' | ||
| env = os.environ.copy() | ||
| env.pop('FOREMANCTL_SYNCED_FOLDER', None) | ||
| env.update({ | ||
| 'PATH': f'{binaries}{os.pathsep}{env["PATH"]}', | ||
| 'ANSIBLE_CONFIG': str(config), | ||
| 'ANSIBLE_LOCAL_TEMP': str(tmp_path / 'ansible-local'), | ||
| 'ANSIBLE_REMOTE_TEMP': str(tmp_path / 'ansible-remote'), | ||
| 'VAGRANT_TEST_LOG': str(log), | ||
| }) | ||
| return tmp_path, env, log | ||
|
|
||
|
|
||
| @pytest.mark.parametrize(('inherited', 'option', 'expected'), [ | ||
| (None, None, 'enabled'), | ||
| ('', None, 'enabled'), | ||
| ('disabled', None, 'disabled'), | ||
| (None, 'disabled', 'disabled'), | ||
| ('disabled', 'enabled', 'enabled'), | ||
| ('enabled', 'disabled', 'disabled'), | ||
| ]) | ||
| def test_vms_shared_folder_setting_reaches_up_and_provision(forge_vms, inherited, option, expected): | ||
| root, env, log = forge_vms | ||
| if inherited is not None: | ||
| env['FOREMANCTL_SYNCED_FOLDER'] = inherited | ||
| command = ['./forge', 'vms', 'start', '--vms', 'quadlet client'] | ||
| if option is not None: | ||
| command += ['--synced-folder', option] | ||
| result = subprocess.run(command, cwd=root, env=env, text=True, capture_output=True) | ||
| assert result.returncode == 0, result.stdout + result.stderr | ||
| assert [json.loads(line) for line in log.read_text().splitlines()] == [ | ||
| [['up', 'quadlet', 'client'], expected], | ||
| [['provision', 'quadlet', 'client'], expected], | ||
| ] | ||
| assert (root / 'inventories/local_vagrant').exists() | ||
|
|
||
|
|
||
| def test_vms_rejects_invalid_shared_folder_option(forge_vms): | ||
| root, env, log = forge_vms | ||
| result = subprocess.run( | ||
| ['./forge', 'vms', 'start', '--synced-folder', 'invalid'], | ||
| cwd=root, env=env, text=True, capture_output=True, | ||
| ) | ||
| assert result.returncode != 0 | ||
| assert 'invalid choice' in result.stderr | ||
| assert not log.exists() |
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.
Script executed:
Repository: theforeman/foremanctl
Length of output: 4066
Script executed:
Repository: theforeman/foremanctl
Length of output: 13425
Skip the synced-folder check for
destroy, orforge vms stopfails.The play sets
FOREMANCTL_SYNCED_FOLDERfrom the inherited environment. The Vagrantfile aborts at load time on any value other thanenabledordisabled.vagrant destroyalso loads the Vagrantfile, so the abort blocks the stop command. Because the destroy task has no error handling, the play fails before any VM is destroyed. The inventory removal task in the same block is skipped.Before this change, the inherited value was ignored, so the stop path succeeded with the same environment.
./forge vms stop --synced-folder enabledavoids the failure, because the play-level value usesvm_synced_folderfirst. Unsetting the variable also avoids it.🐛 Suggested fix
This keeps the validation for
up,provision, andreload. Fordestroy, the invalid value reaches only thedisabled:option, which evaluates tofalseand has no effect.Committable suggestion