Repository: ansible/ansible

Issue:
Blockinfile: insert[before|after] throws: cannot use a string  pattern on a bytes-like object
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
blockinfile.py

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
OS: Ubuntu 16.04 Xenial with Python3 (interpreter is set to Python3)

##### SUMMARY
<!--- Explain the problem briefly -->
Python3 changes the behavior for the search function as it seams. 

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
Only affects insertbefore / insertafter
<!--- Paste example playbooks or commands between quotes below -->
```yaml
  - name: Insert new Prompt
    blockinfile:
      path:            /root/.bashrc
      insertafter:     '###_OLD-PROMPT_###.'
      block: |
               if [ "$USER" == "root" ]; then
                  PS1='${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\]$(__cegit)\[\033[00m\]\$ '
               else
                  PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\]$(__cegit)\[\033[00m\]\$ '
               fi
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
No error should occur. We are only replacing in a ASCII file a part.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Module crash
<!--- Paste verbatim command output between quotes below -->
```
fatal: [******-wi1*********.local]: FAILED! => {"changed": false, "failed": true, "module_stderr": 
"Shared connection to ******-wi1.**********.local closed.\r\n", "module_stdout": 
"Traceback (most recent call last):\r\n  File \"/tmp/ansible_0s3yacif/ansible_module_blockinfile.py\", 
line 334, in <module>\r\n main()\r\n  File \"/tmp/ansible_0s3yacif/ansible_module_blockinfile.py\",
 line 284, in main\r\n    if insertre.search(line):\r\nTypeError: cannot use a string 
pattern on a bytes-like object\r\n", "msg": 
"MODULE FAILURE", "rc": 0}
```

##### BUGFIX
Caution, a developer should verify this, because I'am not firm with Python at all.
Neither with Python 2 / Python 3 differencees

```
FILE: ansible/lib/ansible/modules/files/blockinfile.py
                       Current Source Code                >>          Changed to
255
256    if insertafter not in (None, 'EOF'):
257        insertre = re.compile(insertafter)             >>        insertre = re.compile(b(insertafter))
258    elif insertbefore not in (None, 'BOF'):
259        insertre = re.compile(insertbefore)            >>        insertre = re.compile(b(insertbefore))
260    else:
261        insertre = None
262

```





Discussion:
cc @yaegashi
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
In my case, I fix same problem using to_bytes() instead of b().
```
    if insertafter not in (None, 'EOF'):
        insertre = re.compile(to_bytes(insertafter))
    elif insertbefore not in (None, 'BOF'):
        insertre = re.compile(to_bytes(insertbefore))
    else:
        insertre = None
```
@smellman Your solution worked for me. Thanks. 
Affects me as well on current `devel`.

I've used similar `lineinfile` module for now and it uses `to_bytes(..., errors='surrogate_or_strict')` to convert regex.

Going to make a PR to do the same in `blockinfile`.

Resolving patch:
diff --git a/lib/ansible/modules/files/blockinfile.py b/lib/ansible/modules/files/blockinfile.py
--- a/lib/ansible/modules/files/blockinfile.py
+++ b/lib/ansible/modules/files/blockinfile.py
@@ -253,9 +253,9 @@ def main():
         insertafter = 'EOF'
 
     if insertafter not in (None, 'EOF'):
-        insertre = re.compile(insertafter)
+        insertre = re.compile(to_bytes(insertafter, errors='surrogate_or_strict'))
     elif insertbefore not in (None, 'BOF'):
-        insertre = re.compile(insertbefore)
+        insertre = re.compile(to_bytes(insertbefore, errors='surrogate_or_strict'))
     else:
         insertre = None
 


Test patch: