Repository: ansible/ansible

Issue:
[docker_container] No -w (workdir) option available
##### ISSUE TYPE

 - Feature Idea

##### COMPONENT NAME
`docker_container`

##### ANSIBLE VERSION
```
$ ansible --version
ansible 2.2.0.0
  config file = /home/lalala/ansible/ansible.cfg
  configured module search path = Default w/o overrides

$ cat /home/lalala/ansible/ansible.cfg
[defaults]
host_key_checking = False

[ssh_connection]
ssh_args = -o ForwardAgent=yes
```


##### OS / ENVIRONMENT
```
$ uname -a 
Linux best_machine 4.4.0-57-generic #78-Ubuntu SMP Fri Dec 9 23:50:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
```

##### SUMMARY
The `docker_container` module lacks the `-w (workdir)` `docker run` parameter.

##### WHAT I'D LIKE
I want to run the following docker run command:

    docker run --rm -v ~/code/my_project/:/go/src/my_project golang:alpine go build -w /go/src/my_project -o my_project

Which would build my project inside the `golang:alpine` container. ATM, I'll have to run the command directly using Ansible's `command` module, but I guess a `workdir` parameter would fit well in the (already huge) parameters list of the module, like so:
```yaml
- name: Build project {{ project_name }}
  docker_container:
    image: golang:alpine
    name: "{{ project_name }}"
    command: "go build -o {{ project_name }}"
    volumes: "{{ project_dir }}:/go/src/{{ project_name }}"
    workdir: "/go/src/{{ project_name }}" # This is what I'd like!
    cleanup: yes
```


[docker_container] No -w (workdir) option available
##### ISSUE TYPE

 - Feature Idea

##### COMPONENT NAME
`docker_container`

##### ANSIBLE VERSION
```
$ ansible --version
ansible 2.2.0.0
  config file = /home/lalala/ansible/ansible.cfg
  configured module search path = Default w/o overrides

$ cat /home/lalala/ansible/ansible.cfg
[defaults]
host_key_checking = False

[ssh_connection]
ssh_args = -o ForwardAgent=yes
```


##### OS / ENVIRONMENT
```
$ uname -a 
Linux best_machine 4.4.0-57-generic #78-Ubuntu SMP Fri Dec 9 23:50:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
```

##### SUMMARY
The `docker_container` module lacks the `-w (workdir)` `docker run` parameter.

##### WHAT I'D LIKE
I want to run the following docker run command:

    docker run --rm -v ~/code/my_project/:/go/src/my_project golang:alpine go build -w /go/src/my_project -o my_project

Which would build my project inside the `golang:alpine` container. ATM, I'll have to run the command directly using Ansible's `command` module, but I guess a `workdir` parameter would fit well in the (already huge) parameters list of the module, like so:
```yaml
- name: Build project {{ project_name }}
  docker_container:
    image: golang:alpine
    name: "{{ project_name }}"
    command: "go build -o {{ project_name }}"
    volumes: "{{ project_dir }}:/go/src/{{ project_name }}"
    workdir: "/go/src/{{ project_name }}" # This is what I'd like!
    cleanup: yes
```




Discussion:
My bad! I just tried the parameter anyway, it works! It's only the documentation that needs to be updated (I think...).
@Adrien-Luxey are you sure it works? I just checked the oode an that parameter is not in there.
Not so much, no! What I know is that my build wouldn't work without the workdir option, yet it works. But that's no proof.
I've been through the code too, and couldn't find any reference to 'workdir' anywhere. Since I don't know how ansible works, I was wondering if the argument could have been passed as a keyword argument to docker transparently. 

Still, a demonstration is not hard to do:
```
$ docker run alpine pwd
/
$ docker run -w /home alpine pwd
/home
```

I am trying it out in Ansible, I will get back to you.

EDIT: Done, there *is* an error when trying to use `workdir`. I was using `command` to compile, sorry. So this is the playbook:
```yaml
---
- name: Testing whether workdir is implemented
  hosts: launched
  connection: local

  tasks:
    - name: docker_container without workdir
      docker_container:
        name: without_workdir
        image: alpine
        command: pwd
      register: without
    - debug: "msg={{ without }}"


    - name: docker_container with workdir
      docker_container:
        name: with_workdir
        image: alpine
        workdir: /home
        command: pwd
      register: with_workdir
    - debug: "msg={{ with_workdir }}"
```

Output:
```
 ______________________________________________
< PLAY [Testing whether workdir is implemented] >
 ----------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ______________
< TASK [setup] >
 --------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [localhost]
 _________________________________________
< TASK [docker_container without workdir] >
 -----------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [localhost]
 ______________
< TASK [debug] >
 --------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [localhost] => {
    "msg": {
        "ansible_facts": {}, 
        "changed": true
    }
}
 ______________________________________
< TASK [docker_container with workdir] >
 --------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "msg": "unsupported parameter for module: workdir"}
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

localhost                  : ok=3    changed=1    unreachable=0    failed=1   
```
We do get an "unsupported parameter" error.
@Adrien-Luxey  This seems to be an old feature request #8965 . I would also like it to be added to ansible. There are certain cases when using the `-w`. For example there are many popular images that don't set the `WORKDIR` in their docker file and expect it to be passed to them when executing `docker run -w`.
My bad! I just tried the parameter anyway, it works! It's only the documentation that needs to be updated (I think...).
@Adrien-Luxey are you sure it works? I just checked the oode an that parameter is not in there.
Not so much, no! What I know is that my build wouldn't work without the workdir option, yet it works. But that's no proof.
I've been through the code too, and couldn't find any reference to 'workdir' anywhere. Since I don't know how ansible works, I was wondering if the argument could have been passed as a keyword argument to docker transparently. 

Still, a demonstration is not hard to do:
```
$ docker run alpine pwd
/
$ docker run -w /home alpine pwd
/home
```

I am trying it out in Ansible, I will get back to you.

EDIT: Done, there *is* an error when trying to use `workdir`. I was using `command` to compile, sorry. So this is the playbook:
```yaml
---
- name: Testing whether workdir is implemented
  hosts: launched
  connection: local

  tasks:
    - name: docker_container without workdir
      docker_container:
        name: without_workdir
        image: alpine
        command: pwd
      register: without
    - debug: "msg={{ without }}"


    - name: docker_container with workdir
      docker_container:
        name: with_workdir
        image: alpine
        workdir: /home
        command: pwd
      register: with_workdir
    - debug: "msg={{ with_workdir }}"
```

Output:
```
 ______________________________________________
< PLAY [Testing whether workdir is implemented] >
 ----------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ______________
< TASK [setup] >
 --------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [localhost]
 _________________________________________
< TASK [docker_container without workdir] >
 -----------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [localhost]
 ______________
< TASK [debug] >
 --------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [localhost] => {
    "msg": {
        "ansible_facts": {}, 
        "changed": true
    }
}
 ______________________________________
< TASK [docker_container with workdir] >
 --------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "msg": "unsupported parameter for module: workdir"}
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

localhost                  : ok=3    changed=1    unreachable=0    failed=1   
```
We do get an "unsupported parameter" error.
@Adrien-Luxey  This seems to be an old feature request #8965 . I would also like it to be added to ansible. There are certain cases when using the `-w`. For example there are many popular images that don't set the `WORKDIR` in their docker file and expect it to be passed to them when executing `docker run -w`.

Resolving patch:
diff --git a/lib/ansible/modules/cloud/docker/docker_container.py b/lib/ansible/modules/cloud/docker/docker_container.py
--- a/lib/ansible/modules/cloud/docker/docker_container.py
+++ b/lib/ansible/modules/cloud/docker/docker_container.py
@@ -466,6 +466,12 @@
       - List of container names or Ids to get volumes from.
     default: null
     required: false
+  working_dir:
+    description:
+      - Path to the working directory.
+    default: null
+    required: false
+    version_added: "2.4"
 extends_documentation_fragment:
     - docker
 
@@ -763,6 +769,7 @@ def __init__(self, client):
         self.volume_binds = dict()
         self.volumes_from = None
         self.volume_driver = None
+        self.working_dir = None
 
         for key, value in client.module.params.items():
             setattr(self, key, value)
@@ -866,6 +873,7 @@ def create_parameters(self):
             labels='labels',
             stop_signal='stop_signal',
             volume_driver='volume_driver',
+            working_dir='working_dir',
         )
 
         result = dict(
@@ -1285,7 +1293,8 @@ def has_different_configuration(self, image):
             expected_volumes=config.get('Volumes'),
             expected_binds=host_config.get('Binds'),
             volumes_from=host_config.get('VolumesFrom'),
-            volume_driver=host_config.get('VolumeDriver')
+            volume_driver=host_config.get('VolumeDriver'),
+            working_dir=host_config.get('WorkingDir')
         )
 
         differences = []
@@ -2039,6 +2048,7 @@ def main():
         volumes=dict(type='list'),
         volumes_from=dict(type='list'),
         volume_driver=dict(type='str'),
+        working_dir=dict(type='str'),
     )
 
     required_if = [


Test patch: