Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.
RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.

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-rolesAssignee: Thomas Haller <thaller>
Status: CLOSED ERRATA QA Contact: qe-baseos-daemons
Severity: medium Docs Contact:
Priority: medium    
Version: 7.4CC: hartsjc, jollis, kdixon, mperz, ovasik, pcahyna, tbowling, thaller, till
Target Milestone: rcKeywords: 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:    

Description Jeremy Ollis 2017-09-01 19:19:50 UTC
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.

Comment 2 Thomas Haller 2017-09-12 12:47:59 UTC
> 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?

Comment 4 Thomas Haller 2017-09-19 10:07:33 UTC
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

Comment 5 Pavel Cahyna 2017-09-19 10:51:41 UTC
(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.

Comment 6 Michelle Perz 2017-09-29 15:31:50 UTC
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

Comment 7 James Hartsock 2017-09-29 15:35:54 UTC
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.

Comment 8 Jeremy Ollis 2017-10-13 21:06:07 UTC
Is there an update available for next steps on this issue?

Comment 9 Jeremy Ollis 2017-11-11 00:47:06 UTC
Pinging on this bug.  Is there anything else I can add to the background?

Comment 11 Thomas Haller 2017-11-17 11:56:44 UTC
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.

Comment 14 James Hartsock 2018-02-05 02:44:07 UTC
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 
~~~

Comment 15 Leos Pol 2018-02-26 19:43:58 UTC
rhel-system-roles-0.6-1.el7 verified based on comment 14. Thanks

Comment 18 errata-xmlrpc 2018-03-07 09:53:26 UTC
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

Comment 19 Pavel Cahyna 2018-03-09 14:16:02 UTC
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.

Comment 20 James Hartsock 2018-03-14 15:21:48 UTC
Thank you, much needed information for these new features!