Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

k8s_cp doesn't work correctly when deployed container's WORKDIR is other than '/' #222

Closed
itaru2622 opened this issue Sep 4, 2021 · 2 comments · Fixed by #223
Closed
Labels
has_pr needs_verify type/bug Something isn't working

Comments

@itaru2622
Copy link
Contributor

itaru2622 commented Sep 4, 2021

SUMMARY

k8s_cp doesn't work correctly when k8s container deployed with WORKDIR other than '/'.
on uploading( state:to_pod ), k8s_cp copies to ${WORKDIR}/${remote_path} but not ${remote_path} even given remote_path is full path ('/tmp/...')

some docker image sets WORKDIR(workingDir in k8s) other than '/' , like official golang image sets to /go,
then, k8s_cp cannot work with such container.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

not sure but may be somewhere kubernetes.core.k8s_cp to
https://github.com/kubernetesclient/python/blob/master/kubernetes/client/api/core_v1_api.py

ANSIBLE VERSION
# ansible --version
ansible [core 2.11.4] 
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.9/dist-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110]
  jinja version = 3.0.1
  libyaml = True

COLLECTION VERSION

I install kubernetes.core with latest github main branch

ansible-galaxy collection list kubernetes.core
# /root/.ansible/collections/ansible_collections
Collection      Version
--------------- -------
kubernetes.core 2.1.1  

# /usr/local/lib/python3.9/dist-packages/ansible_collections
Collection      Version
--------------- -------
kubernetes.core 1.2.1  

CONFIGURATION
# ansible-config dump --only-changed

OS / ENVIRONMENT

debian:bullseye

STEPS TO REPRODUCE
  • install latest kubernetes.core by
    ansible-galaxy collection install git+https://github.com/ansible-collections/kubernetes.core.git

  • deploy container on k8s with "workingDir:/otherthanRoot" (official golang image is easy to test)

  • k8s_cp with {local_path: /tmp/any.txt, remote_path: /tmp/any.txt, state: to_pod }

  • k8s_cp returns without error.

  • login the container shell with "kubectl exec ...", and check if /tmp/any.txt is exist.
    => file is uploaded in wrong path, ${workingDir}/tmp/any.txt but not /tmp/any.txt

  • official golang image set WORK_DIR as /go so, it cannot upload to golang based container.

Following are my test codes.
ansible-playbook -i hosts -e test=alpine:latest
=> when workindDir is '/home' => failed always (uploaded in wrong path, even official alpine nor debian)
=> if workingDir is '/', => succeeded (official golang as well)
=> if workingDir is undefined => depends on images's WORKDIR (may '/', '/go', ...)

- name: bootstrap ansible test
  hosts: localhost
  gather_facts: no
  connection: local
  tasks:
   - ...
---
- name: setup
  block:
  - set_fact:
      images: [ "alpine:latest", "golang:alpine", "debian:bullseye", "golang:bullseye" ]
#     workingDir: "/"
      workingDir: "/home"
      kubeconfig: "/root/.kube/config"
      cases: "{{ [] }}"
  - set_fact:
      cases: |
        {{ cases + [{  'image': item , 'container': item|replace(':','-')|replace('/','-')|replace('.','')  }] }}
    with_items: "{{ images }}"
    
  - template:
      src: "pod-template.j2"
      dest: "/tmp/pod-sample.yaml"
  - k8s:
      state: present
      src: "/tmp/pod-sample.yaml"
      kubeconfig: "{{ kubeconfig }}"

  - name: wait pod ready (this doesn't work in some cases...)
    command: |
       kubectl wait pod --for=condition=ready --kubeconfig {{kubeconfig}} sample-0 --timeout=150s

  - name: prepare content
    copy:
      dest: "/tmp/{{item}}.sh"
      content: |
         #!/bin/sh
         echo "{{item}}" > /tmp/{{item}}.txt
         date            >> /tmp/{{item}}.txt
      mode: +x
    with_items: "{{ cases | map(attribute='container')| list }}"

- name: "test : {{ test }}"
  set_fact:
    target: "{{ test |replace(':','-')|replace('/','-')| replace('.','') }}"

- name: test  {{ target }}
  block:
    - include_tasks: "k8s-test.yaml"
      vars:
        container: "{{ target }}"
        namespace:  "default"
        pod:        "sample-0"
        shell:      "/bin/sh -c"
        upload: { 'local_path': "/tmp/{{target}}.sh", 'remote_path':"/tmp/{{target}}1.sh" }
        exec: |
           rm -f /tmp/{{target}}.txt
           /tmp/{{target}}1.sh
        download: { 'remote_path': "/tmp/{{target}}.txt", 'local_path': "/tmp/{{target}}1.txt" }
    - debug:
        msg: "got: {{ lookup('file', '/tmp/{{target}}1.txt') }}"
---
# k8s-test.yaml

#- name: set target container on k8s
# set_fact:
#    namespace: "default"
#    pod:       "sample"
#    shell:     "/bin/sh -c"
#    container: "alpine-latest"

- name: "uploading     x       core.k8s_cp"
  when: upload is defined
  kubernetes.core.k8s_cp:
    state:         to_pod 
    kubeconfig:    "{{ kubeconfig }}"
    namespace:     "{{ namespace }}"
    pod:           "{{ pod }}"
    container:     "{{ container }}"
    local_path:    "{{ upload.local_path }}"
    remote_path:   "{{ upload.remote_path }}"

- name: "exec          x       core.k8s_exec"
  when: exec is defined
  kubernetes.core.k8s_exec:
     kubeconfig:   "{{ kubeconfig }}"
     namespace:    "{{ namespace }}"
     pod:          "{{ pod }}"
     container:    "{{ container }}"
     command: >-
        {{shell}} '{{ exec }}'
  register: result

- name: "result of remote exection"
  debug:
    var: result

- name: "downloading   x       core.k8s_cp"
  when: download is defined
  kubernetes.core.k8s_cp:
     state: from_pod
     kubeconfig:   "{{ kubeconfig }}"
     namespace:    "{{ namespace }}"
     pod:          "{{ pod }}"
     container:    "{{ container }}"
     remote_path:  "{{ download.remote_path }}"
     local_path:   "{{ download.local_path }}"
---
# pod-template.j2
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: "sample"
  namespace: "default"
spec:
  selector:
    matchLabels:
      k8s-app: "sample"
  serviceName: "sample"
  replicas: 1
  template:
    metadata:
      labels:
        k8s-app: "sample"
    spec:
      containers:
{% for node in cases %}
      - name: {{ node.container }}
        image: {{ node.image }}
        imagePullPolicy: IfNotPresent
{%   if workingDir is defined %}
        workingDir: {{ workingDir }}
{%   endif %}
        command:
          - sh
          - "-c"
          - |
            tail -f /dev/null
{% endfor %}
EXPECTED RESULTS

if path (remote_path or local_path) is started with '/' (i.e. full path),
then k8s_cp should upload/download to the given path but not other place ( ${workingDir}/* )

ACTUAL RESULTS

k8s_cp upload files under ${workingDir}/tmp/... even remote_file is specified to /tmp/...


@itaru2622
Copy link
Contributor Author

itaru2622 commented Sep 5, 2021

to maintainers,
I investigated some about this issue and found that:

  • k8s_cp just calls REST API of /api/v1/namespaces/{namespace}/pods/{name}/execusing via connect_get_namespaced_pod_exec in kubernetes.client.api.core_v1_api

  • there is no param to change directory before executing command in the above REST API.

  • fortunately, tar command (which k8s_cp using) has special option '-C /changeDirectoryBeforeExection'.
    so appending '-C /' may be easiest way when full path specified.

@abikouo
Copy link
Contributor

abikouo commented Sep 7, 2021

Hi @itaru2622

Thanks for taking the time to report this issue and provide full details to reproduce.
Thanks also for the pull request, we will take some time to review it.

ansible-zuul bot pushed a commit that referenced this issue Sep 13, 2021
#223)

fix k8s_cp uploading when deployed container's WORKDIR is other than '/'

SUMMARY


fix #222
ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

k8s_cp
ADDITIONAL INFORMATION

Reviewed-by: Mike Graves <mgraves@redhat.com>
Reviewed-by: None <None>
Reviewed-by: None <None>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has_pr needs_verify type/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants