Repository: ansible/ansible-modules-core

Issue:
mount module _escape_fstab doesn't handle integers
When I ran the mount module I got the following error:

```
/scp:r35: #$ python ~/.ansible/tmp/ansible-tmp-1438625022.07-152487730049288/mount
Traceback (most recent call last):
  File "/root/.ansible/tmp/ansible-tmp-1438625022.07-152487730049288/mount", line 2079, in <module>
    main()
  File "/root/.ansible/tmp/ansible-tmp-1438625022.07-152487730049288/mount", line 354, in main
    name, changed = set_mount(module, **args)
  File "/root/.ansible/tmp/ansible-tmp-1438625022.07-152487730049288/mount", line 134, in set_mount
    escaped_args = dict([(k, _escape_fstab(v)) for k, v in args.iteritems()])
  File "/root/.ansible/tmp/ansible-tmp-1438625022.07-152487730049288/mount", line 110, in _escape_fstab
    return v.replace('\\', '\\134').replace(' ', '\\040').replace('&', '\\046')
AttributeError: 'int' object has no attribute 'replace'
```

I replaced the body of `_escape_fstab` with:

``` python
def _escape_fstab(v):
    """ escape space (040), ampersand (046) and backslash (134) which are invalid in fstab fields """
    if hasattr(v, 'replace') and callable(getattr(v, 'replace')):
        return v.replace('\\', '\\134').replace(' ', '\\040').replace('&', '\\046')
    else:
        return v
```

And that did the trick.

This is on an OL6u6 box running Python 2.6.6 ...



Discussion:
Oh - the commit that introduced the problem was dadc1faebd9a177f66f39830d4c65efe9d559870

# Can You Help Us Out?

Thanks for filing a ticket! I am the friendly GitHub Ansibot.

It looks like you might not have filled out the issue description based on our standard issue template.  You might not have known about that, and that's ok too, we'll tell you how to do it.

We have a standard template because Ansible is a really busy project and it helps to have some standard information in each ticket, and GitHub doesn't yet provide a standard facility to do this like some other bug trackers.  We hope you understand as this is really valuable to us!.

Solving this is simple: please copy the contents of this [template](https://raw.githubusercontent.com/ansible/ansible/devel/ISSUE_TEMPLATE.md) and **paste it into the description** of your ticket.  That's it!

# If You Had A Question To Ask Instead

If you happened to have a "how do I do this in Ansible" type of question, that's probably more of a user-list question than a bug report, and you should probably ask this question on the project mailing list instead.

However, if you think you have a bug, the report is the way to go!  We definitely want all the bugs filed :)  Just trying to help!

# About Priority Tags

Since you're here, we'll also share some useful information at this time.

In general tickets will be assigned a priority between P1 (highest) and P5, and then worked in priority order. We may also have some follow up questions along the way, so keeping up with follow up comments via GitHub notifications is a good idea.

Due to large interest in Ansible, humans may not comment on your ticket immediately.

# Mailing Lists

If you have concerns or questions, you're welcome to stop by the ansible-project or ansible-development mailing lists, as appropriate.  Here are the links:
- https://groups.google.com/forum/#!forum/ansible-project - for discussion of bugs and how-to type questions
- https://groups.google.com/forum/#!forum/ansible-devel - for discussion on how to implement a code change, or feature brainstorming among developers

Thanks again for the interest in Ansible!

Hello TobyHFerguson,

I am having difficulties reproducing this bug condition.  Would you please use the template above to post more background for this error (in particular, how you call the mount module) so that we may better able to resolve it?

Thanks,
Chares

Hello,

I ran into the same problem. This produces the stacktrace for me:

```
- name: Write swap entry in fstab
  mount:
    name: none
    src: "{{ swap_file_path }}"
    fstype: swap
    opts: sw
    passno: 0
    dump: 0
    state: present
```

This instead works:

```
- name: Write swap entry in fstab
  mount:
    name: none
    src: "{{ swap_file_path }}"
    fstype: swap
    opts: sw
    passno: "0"
    dump: "0"
    state: present
```

Same here.

This works:

```
- name: mount /tmp/nginx_cache ramdisk
  mount:
    name:   '/tmp/nginx_cache'
    src:    tmpfs
    fstype: tmpfs
    opts:   'nodev,nosuid,noexec,nodiratime,size={{ nginx_tmpfs_size }}m'
    dump:   '0'
    passno: '0'
```

while using `dump: 0` and `passno: 0` yields stacktraces like this:

```
fatal: [hostname]: FAILED! => {"changed": false, "failed": true, "module_stderr": "", "module_stdout": "Traceback (most recent call last):\r\n  File \"/home/ansible/.ansible/tmp/ansible-tmp-1453111306.24-257420139891020/mount\", line 2321, in <module>\r\n    main()\r\n  File \"/home/ansible/.ansible/tmp/ansible-tmp-1453111306.24-257420139891020/mount\", line 354, in main\r\n    name, changed = set_mount(module, **args)\r\n  File \"/home/ansible/.ansible/tmp/ansible-tmp-1453111306.24-257420139891020/mount\", line 134, in set_mount\r\n    escaped_args = dict([(k, _escape_fstab(v)) for k, v in args.iteritems()])\r\n  File \"/home/ansible/.ansible/tmp/ansible-tmp-1453111306.24-257420139891020/mount\", line 110, in _escape_fstab\r\n    return v.replace('\\\\', '\\\\134').replace(' ', '\\\\040').replace('&', '\\\\046')\r\nAttributeError: 'int' object has no attribute 'replace'\r\n", "msg": "MODULE FAILURE", "parsed": false}
```


Resolving patch:
diff --git a/system/mount.py b/system/mount.py
--- a/system/mount.py
+++ b/system/mount.py
@@ -106,7 +106,10 @@ def write_fstab(lines, dest):
 
 def _escape_fstab(v):
     """ escape space (040), ampersand (046) and backslash (134) which are invalid in fstab fields """
-    return v.replace('\\', '\\134').replace(' ', '\\040').replace('&', '\\046')
+    if isinstance(v, int):
+        return v
+    else:
+        return v.replace('\\', '\\134').replace(' ', '\\040').replace('&', '\\046')
 
 def set_mount(module, **kwargs):
     """ set/change a mount point location in fstab """
@@ -120,11 +123,6 @@ def set_mount(module, **kwargs):
     )
     args.update(kwargs)
 
-    # save the mount name before space replacement
-    origname =  args['name']
-    # replace any space in mount name with '\040' to make it fstab compatible (man fstab)
-    args['name'] = args['name'].replace(' ', r'\040')
-
     new_line = '%(src)s %(name)s %(fstype)s %(opts)s %(dump)s %(passno)s\n'
 
     to_write = []
@@ -164,14 +162,13 @@ def set_mount(module, **kwargs):
             to_write.append(line)
 
     if not exists:
-        to_write.append(new_line % args)
+        to_write.append(new_line % escaped_args)
         changed = True
 
     if changed and not module.check_mode:
         write_fstab(to_write, args['fstab'])
 
-    # mount function needs origname
-    return (origname, changed)
+    return (args['name'], changed)
 
 
 def unset_mount(module, **kwargs):
@@ -186,11 +183,6 @@ def unset_mount(module, **kwargs):
     )
     args.update(kwargs)
 
-    # save the mount name before space replacement
-    origname =  args['name']
-    # replace any space in mount name with '\040' to make it fstab compatible (man fstab)
-    args['name'] = args['name'].replace(' ', r'\040')
-
     to_write = []
     changed = False
     escaped_name = _escape_fstab(args['name'])
@@ -220,8 +212,7 @@ def unset_mount(module, **kwargs):
     if changed and not module.check_mode:
         write_fstab(to_write, args['fstab'])
 
-    # umount needs origname
-    return (origname, changed)
+    return (args['name'], changed)
 
 
 def mount(module, **kwargs):


Test patch: