Skip to content

Commit

Permalink
apt_repository: Do not convert symlink repo to a normal file (ansible…
Browse files Browse the repository at this point in the history
…#82271)

* apt_repository: Do not convert symlink repo to a normal file

* module manually writes to repo files. If the file is a symlink
  module used to re-write and convert a symlink to a normal file.
  This fix tracks the symlink and keeps the changes intact.

Fixes: ansible#49809

Signed-off-by: Abhijeet Kasurde <[email protected]>
  • Loading branch information
Akasurde authored Nov 28, 2023
1 parent e6e19e3 commit 265f5e7
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 2 deletions.
3 changes: 3 additions & 0 deletions changelogs/fragments/49809_apt_repository.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- apt_repository - do not modify repo files if the file is a symlink (https://github.com/ansible/ansible/issues/49809).
11 changes: 9 additions & 2 deletions lib/ansible/modules/apt_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ class SourcesList(object):
def __init__(self, module):
self.module = module
self.files = {} # group sources by file
self.files_mapping = {} # internal DS for tracking symlinks
# Repositories that we're adding -- used to implement mode param
self.new_repos = set()
self.default_file = self._apt_cfg_file('Dir::Etc::sourcelist')
Expand All @@ -240,6 +241,8 @@ def __init__(self, module):

# read sources.list.d
for file in glob.iglob('%s/*.list' % self._apt_cfg_dir('Dir::Etc::sourceparts')):
if os.path.islink(file):
self.files_mapping[file] = os.readlink(file)
self.load(file)

def __iter__(self):
Expand Down Expand Up @@ -372,7 +375,11 @@ def save(self):
f.write(line)
except IOError as ex:
self.module.fail_json(msg="Failed to write to file %s: %s" % (tmp_path, to_native(ex)))
self.module.atomic_move(tmp_path, filename)
if filename in self.files_mapping:
# Write to symlink target instead of replacing symlink as a normal file
self.module.atomic_move(tmp_path, self.files_mapping[filename])
else:
self.module.atomic_move(tmp_path, filename)

# allow the user to override the default mode
if filename in self.new_repos:
Expand Down Expand Up @@ -417,7 +424,7 @@ def modify(self, file, n, enabled=None, source=None, comment=None):
def _add_valid_source(self, source_new, comment_new, file):
# We'll try to reuse disabled source if we have it.
# If we have more than one entry, we will enable them all - no advanced logic, remember.
self.module.log('ading source file: %s | %s | %s' % (source_new, comment_new, file))
self.module.log('adding source file: %s | %s | %s' % (source_new, comment_new, file))
found = False
for filename, n, enabled, source, comment in self:
if source == source_new:
Expand Down
40 changes: 40 additions & 0 deletions test/integration/targets/apt_repository/tasks/apt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,46 @@
- result is failed
- result.msg == 'Please set argument \'repo\' to a non-empty value'

#
# TEST: keep symlink
#
- import_tasks: 'cleanup.yml'

- name: install local-apt-repository with apt
apt: pkg=local-apt-repository state=present

- name: Check if local apt repo file is a symlink
stat:
path: /etc/apt/sources.list.d/local-apt-repository.list
register: stat_result

- name: Assert if local apt repo file is a symlink
assert:
that:
- stat_result.stat.islnk is defined and stat_result.stat.islnk
- stat_result.stat.lnk_source == "/usr/lib/local-apt-repository/local-apt-repository.list"

- name: Try installing an invalid repo
apt_repository:
repo: deb http://dl.google.com/linux/chrome/deb2/ stable main
state: present
filename: google-chrome
ignore_errors: true

- name: Check the stat for the given symlink
stat:
path: /etc/apt/sources.list.d/local-apt-repository.list
register: stat_result2

- name: Assert that the symlink is intact after apt_repository operation
assert:
that:
- stat_result2.stat.islnk is defined and stat_result2.stat.islnk
- stat_result2.stat.lnk_source == "/usr/lib/local-apt-repository/local-apt-repository.list"

- name: uninstall local-apt-repository with apt
apt: pkg=local-apt-repository state=absent purge=yes

#
# TEARDOWN
#
Expand Down

0 comments on commit 265f5e7

Please sign in to comment.