Bug 1487747
| Summary: | 'network' role silently deletes /etc/sysconfig/network-scripts/routes-<interface> file when using initscripts | ||
|---|---|---|---|
| Product: | Red Hat Enterprise Linux 7 | Reporter: | Jeremy Ollis <jollis> |
| Component: | rhel-system-roles | Assignee: | Thomas Haller <thaller> |
| Status: | CLOSED ERRATA | QA Contact: | qe-baseos-daemons |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | 7.4 | CC: | hartsjc, jollis, kdixon, mperz, ovasik, pcahyna, tbowling, thaller, till |
| Target Milestone: | rc | Keywords: | Extras |
| Target Release: | --- | ||
| Hardware: | Unspecified | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | rhel-system-roles-0.6-1.el7 | Doc Type: | If docs needed, set a value |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2018-03-07 09:53:26 UTC | Type: | Bug |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
| Bug Depends On: | 1539912 | ||
| Bug Blocks: | |||
> Produces a warning in check mode: > > [WARNING]: <info> #0, state:present, "enp1s0": ifcfg-rh profile "enp1s0" > already up to date > > [WARNING]: <info> #1, state:present, "enp1s0.29": update ifcfg-rh profile > "enp1s0.29" Technically, everything that the role logs is a [WARNING]. That is because (AFAIK) the ansible module has no way to do debug logging only. The <info> tells you that this is not serious warning but purely informational. Otherwise, it would be pretty cryptic to understandstand what the role is doing. Sure, this should be improved, but I think it needs infrastructure from ansible to be able to produce debug logging (or somebody explain me how to achieve that). The "update ifcfg-rh profile" message says that the ifcfg connection profile differs on disk and needs to be written. A ifcfg-profile consists of several files (or their absence). Hence, the role deletes files like role-* and route-* (provided that the profile doesn't specify any rules/routes -- which currently isn't supported). That is intended. Why is that wrong? Thanks for the response, but sorry, I am not convinced. Ansible is not an interactive program and is not meant to be. It cannot (easily) ask for confirmation from the user. You call it with the appropriate options and it does something. Possibly you run it on multiple hosts simultaneously. ansible has a --check option, which is also implemented by this network role. You can use --check to see what the play would do. Yes, --check is not the default, by default the play modifies the system. > or we need to follow a standard and not over write user configuration without > forced acknowledgment. The point of running the playbook is to configure the system. There is no distinction between "user configuration" and otherwise. Clearly the initscripts are systemwide configuration, and subject to be written by the network role. It seems not surprising to me that running the playbook will modify the connections on the system (depending on the playbook). That possibly involves rewriting ifcfg files. The route-* files are part of the ifcfg files, and if there are no routes, they will be deleted. What else should happen? That isn't fundamentally different from having an ifcfg file with DNS1=8.8.8.8 and then running the play that configures no DNS servers. That will result in removing the DNS1 variable from the ifcfg file. Likewise, defining no routes will result in deletion of the route-* file. The only difference is, that in the DNS1 example the information was removed from the ifcfg-* file (the file itself is still there), while in the route example, the information was removed with the route-* file together. Maybe an RFE for the network role to create backups makes sense. Similar to the "backup" option of the copy module [1]. But note that for the copy module the default is also "no". - Without a mechanism to restore previous backups, backups don't seem useful to do inside the network role itself. Implementing a mechanism to restore previous backups inside the network role, seems overkill. - If you want backups, run another play that creates backups (e.g. via rsync, copy files somewhere, or create a snapshot of the filesystem). Whatever suits you best. The network role wouldn't know. The network role is not a backup tool. Use a backup tool (or a dedicated playbook) to make backups and restore them however you wish. - If you manage the host via ansible, it's not why you need a backup of the host configuration. Backup your ansible playbook, and if the configuration is messed up, re-run the playbook. [1] https://docs.ansible.com/ansible/latest/copy_module.html (In reply to Thomas Haller from comment #4) > - If you manage the host via ansible, it's not why you need a backup of the > host configuration. Backup your ansible playbook, and if the > configuration is > messed up, re-run the playbook. I think the problematic case is when you haven't been managing the host via ansible yet and run the playbook for the first time. Hi Thomas, As Pavel indicated, I think this is just going to be a new experience for a lot of people running Ansible for the first time. Perhaps a call out in the README or a warning in the task header like - name: "Configure networking connection profiles--WARNING will delete existing files outside of specified profile" Thanks, Michelle Agree need the warning, and probably should also be clearly visible when preview the playbook. But think longer term system-roles needs to support static routes, and with that include option that allows admin to have ansible not modify the existing defined static routing. Is there an update available for next steps on this issue? Pinging on this bug. Is there anything else I can add to the background? For one, the bug suggest that running the role should not silently delete a file, but warn? As explained, that is not going to change. Running the role without --dry-run is supposed to change the system. There is no place for user-feedback, it can only fail entirely or do the job. As to deleting the routes file, that is also intended. The route-* and route6-* file are part of the connection profile. When ansible creates/updates/modifies the profile, they are modified to match whatever the role wants. The problem is, that currently the role doesn't support manual/static routes. So, this means to always delete these files. https://github.com/linux-system-roles/network/pull/21 adds support for routes. It also adds a new setting "route_append_only" (which defaults to False). With this you could actually get the desired behavior of not touching route-*/route6-* files, by setting "route_append_only=True", and leaving the "route" list empty. merged upstream: https://github.com/linux-system-roles/network/commit/5e29382bc909dbb784e4dc3e67cbb48c87073e60 Things look good to me here!
Replicating issue with previous version, can see route file is no longer present on client amber!
~~~
[root@amber ~]# cat /etc/sysconfig/network-scripts/route-enp5s0f0
192.168.2.0/24 dev enp5s0f0
# rpm -q rhel-system-roles
rhel-system-roles-0.5-3.el7.noarch
# ansible-playbook -l amber.jjhartsock.com network.yml
# cat /etc/sysconfig/network-scripts/route-enp5s0f0
cat: /etc/sysconfig/network-scripts/route-enp5s0f0: No such file or directory
~~~
With the test RPM things are working
~~~
# yum localinstall /tmp/rhel-system-roles-0.6-1.el7.noarch.rpm
# rpm -q rhel-system-roles
rhel-system-roles-0.6-1.el7.noarch
# grep -v '^[[:space:]]*#' network.yml
---
- hosts: amber.jjhartsock.com
vars:
network_provider: initscripts
network_connections:
- name: enp5s0f0
interface_name: enp5s0f0
type: ethernet
state: up
autoconnect: yes
ip:
route_append_only: True
dhcp4: no
auto6: no
address:
- 10.0.0.1/30
roles:
- role: rhel-system-roles.network
# ansible-playbook -l amber.jjhartsock.com network.yml
[root@amber ~]# cat /etc/sysconfig/network-scripts/route-enp5s0f0
192.168.2.0/24 dev enp5s0f0
~~~
rhel-system-roles-0.6-1.el7 verified based on comment 14. Thanks Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://access.redhat.com/errata/RHBA-2018:0439 The new options are lacking documentation. I am tracking the doc updates in bz1550128. Documentation updates are proposed in https://github.com/linux-system-roles/network/pull/36. Please review. Thank you, much needed information for these new features! |
Description of problem: The 'network' role deletes existing files in /etc/sysconfig/network-scripts that are not of certain types, without warning or asking, including `routes-<interface>' files. How reproducible: Run the role targeting an interface with an existing 'routes-*' file. Steps to Reproduce: 1. Set up these variables network_provider: "initscripts" network_connections: - name: "enp1s0" type: "ethernet" interface_name: "enp1s0" state: "present" ip: dhcp4: "no" auto6: "no" - name: "enp1s0.29" type: "vlan" parent: "enp1s0" state: "present" vlan_id: 29 ip: dhcp4: "no" auto6: "no" address: - "10.0.0.42/25" 2. Run with routes file existing Actual results: Produces a warning in check mode: [WARNING]: <info> #0, state:present, "enp1s0": ifcfg-rh profile "enp1s0" already up to date [WARNING]: <info> #1, state:present, "enp1s0.29": update ifcfg-rh profile "enp1s0.29" Deletes file silently in normal mode Expected results: Fail with error or prompt for action or warn and retain the file. Additional info: We *think* the following is the sequence of events internally within `network_connections.py`, but take this with a grain of salt as we haven't spent a lot of time troubleshooting. - we're using initscripts, so only ifcfg files should be created This method: ``` class Cmd_initscripts(Cmd): def run_state_present(self, idx): . . new_content = IfcfgUtil.content_from_dict(ifcfg_all) ``` Ends up calling: ``` @classmethod def content_from_dict(cls, ifcfg_all, file_type = None): . . if file_type != 'ifcfg': content[file_type] = None continue ``` which would clear out any non 'ifcfg' filetypes from the dict and then calls: ``` try: IfcfgUtil.content_to_file(name, new_content) ``` which does this: ``` @classmethod def content_to_file(cls, name, content, file_type = None): for file_type in cls._file_types(file_type): path = cls.ifcfg_path(name, file_type) h = content[file_type] if h is None: try: os.unlink(path) except OSError as e: import errno if e.errno != errno.ENOENT: raise else: with open(path, 'w') as text_file: text_file.write(h) ``` And that's where we think the file is being silently deleted (the os.unlink(path) ). We think this is related to these extra file types ``` class IfcfgUtil: FILE_TYPES = [ 'ifcfg', 'keys', 'route', 'route6', 'rule', 'rule6', ] ``` so anything not 'ifcfg' gets deleted.