Repository: ansible/ansible

Issue:
add follow to authorized_key to enable following symlinks instead of overwriting them.
From @le9i0nx on 2016-02-20T18:42:59Z
##### Issue Type:
- Bug Report
##### Component Name:

module [authorized_key](http://docs.ansible.com/ansible/authorized_key_module.html)
##### Ansible Version:

```
ansible 2.0.0.2
```
##### Ansible Configuration:

```
[defaults]
filter_plugins = /etc/ansible/filter_plugins:/usr/share/ansible/plugins/filter
lookup_plugins = /etc/ansible/lookup_plugins:/usr/share/ansible/plugins/lookup

hostfile       = /etc/ansible/hosts
remote_tmp     = $HOME/.ansible/tmp
pattern        = *
forks          = 5
poll_interval  = 15
sudo_user      = root
transport      = smart
remote_port    = 22
module_lang    = C

gathering = implicit
sudo_exe = sudo
timeout = 10
ansible_managed = Ansible managed: modified on %Y-%m-%d %H:%M:%S

[accelerate]
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
accelerate_daemon_timeout = 30
```
##### Environment:

debina 8 
##### Summary:

If you change the key replaces the symbolic link.
##### Steps To Reproduce:

For bugs, please show exactly how to reproduce the problem. For new
features, show how the feature would be used.

```
- hosts: remote
  remote_user: root
  tasks:

  - name: Configure ~/.ssh/authorized_keys for users
    authorized_key:
      key: "ssh-key ... root@local"
      state: 'present'
      user: 'root'
```
##### Expected Results:

A symbolic link should be a symbolic link.

```
root@pve32:~/.ssh# ls -la
total 20
drwx------  2 root root 4096 Feb 20 11:58 .
drwx------ 10 root root 4096 Feb 20 11:57 ..
lrwxrwxrwx  1 root root   29 Feb 20 11:58 authorized_keys -> /etc/pve/priv/authorized_keys
-rw-r-----  1 root root   96 Feb 19 13:51 config
-rw-------  1 root root 1679 Feb 19 13:51 id_rsa
-rw-r--r--  1 root root  410 Feb 19 13:51 id_rsa.pub
```
##### Actual Results:

Link to file is replaced if the key is added.

```
root@pve32:~/.ssh# ls -la
total 24
drwx------  2 root root     4096 Feb 20 12:27 .
drwx------ 10 root root     4096 Feb 20 12:26 ..
-rw-------  1 root www-data 1553 Feb 20 12:27 authorized_keys
-rw-r-----  1 root root       96 Feb 19 13:51 config
-rw-------  1 root root     1679 Feb 19 13:51 id_rsa
-rw-r--r--  1 root root      410 Feb 19 13:51 id_rsa.pub
```

Copied from original issue: ansible/ansible-modules-core#3083



Discussion:
From @ansibot on 2016-02-20T18:42:59Z

<!-- @le9i0nx: Thanks for filing this bug report! -->

@ansible ping, this issue is waiting for your response.
[click here for bot help](https://github.com/jctanner/ansibullbot/blob/ISSUE_TRIAGE_CLASS/ISSUE_HELP.md)

<!--- boilerplate: issue_bug_new --->

From @le9i0nx on 2016-02-20T18:42:59Z

needs_contributor


Resolving patch:
diff --git a/lib/ansible/modules/system/authorized_key.py b/lib/ansible/modules/system/authorized_key.py
--- a/lib/ansible/modules/system/authorized_key.py
+++ b/lib/ansible/modules/system/authorized_key.py
@@ -78,6 +78,12 @@
         cases such as fetching it from GitHub or GitLab.
       - If no comment is specified, the existing comment will be kept.
     version_added: "2.4"
+  follow:
+    description:
+      - Follow path symlink instead of replacing it
+    type: bool
+    default: 'no'
+    version_added: "2.7"
 author: "Ansible Core Team"
 '''
 
@@ -284,7 +290,7 @@ def values(self):
         return [item[1] for item in self.items()]
 
 
-def keyfile(module, user, write=False, path=None, manage_dir=True):
+def keyfile(module, user, write=False, path=None, manage_dir=True, follow=False):
     """
     Calculate name of authorized keys file, optionally creating the
     directories and file, properly setting permissions.
@@ -293,11 +299,16 @@ def keyfile(module, user, write=False, path=None, manage_dir=True):
     :param bool write: if True, write changes to authorized_keys file (creating directories if needed)
     :param str path: if not None, use provided path rather than default of '~user/.ssh/authorized_keys'
     :param bool manage_dir: if True, create and set ownership of the parent dir of the authorized_keys file
+    :param bool follow: if True symlinks will be followed and not replaced
     :return: full path string to authorized_keys for user
     """
 
     if module.check_mode and path is not None:
         keysfile = path
+
+        if follow:
+            return os.path.realpath(keysfile)
+
         return keysfile
 
     try:
@@ -314,6 +325,9 @@ def keyfile(module, user, write=False, path=None, manage_dir=True):
         sshdir = os.path.dirname(path)
         keysfile = path
 
+    if follow:
+        keysfile = os.path.realpath(keysfile)
+
     if not write:
         return keysfile
 
@@ -518,6 +532,7 @@ def enforce_state(module, params):
     key_options = params.get("key_options", None)
     exclusive = params.get("exclusive", False)
     comment = params.get("comment", None)
+    follow = params.get('follow', False)
     error_msg = "Error getting key from: %s"
 
     # if the key is a url, request it and use it as key source
@@ -613,7 +628,7 @@ def enforce_state(module, params):
             do_write = True
 
     if do_write:
-        filename = keyfile(module, user, do_write, path, manage_dir)
+        filename = keyfile(module, user, do_write, path, manage_dir, follow)
         new_content = serialize(existing_keys)
 
         diff = None
@@ -650,6 +665,7 @@ def main():
             exclusive=dict(default=False, type='bool'),
             comment=dict(required=False, default=None, type='str'),
             validate_certs=dict(default=True, type='bool'),
+            follow=dict(default=False, type='bool')
         ),
         supports_check_mode=True
     )


Test patch: