ansible-collections / community.docker

Community Docker Collection for Ansible: modules and plugins for working with Docker
https://galaxy.ansible.com/ui/repo/published/community/docker/
GNU General Public License v3.0
197 stars 110 forks source link

docker_plugin fails if plugin exists and plugin_options are set #211

Open lmergner opened 3 years ago

lmergner commented 3 years ago
SUMMARY

docker plugin throws an error when it tries to set an activated plugin. If a plugin already exists, but you have plugin_options: {<options>} in the task, it will fail instead of modifying the plugin.

It's also unclear from the docs whether I need to install (state: present) before I enable (state: enabled) a plugin using ansible. If I enable it, does the module also install it?

This might be a reason to have a docker_plugin_info since, using ansible, I cannot read docker plugin ls — and docker_host_info does not include a section for plugins. If I know which plugins are installed and enabled, we can conditionally install, disable, reconfigure, etc. Using command: docker plugin ls is a bit of an anti-pattern isn't it?

ISSUE TYPE
COMPONENT NAME

community.docker.docker_plugin

ANSIBLE VERSION
ansible [core 2.11.5]
  config file = /Users/lmerg/code/cluster/ansible.cfg
  configured module search path = ['/Users/lmerg/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/lmerg/.pyenv/versions/3.9.5/envs/cluster/lib/python3.9/site-packages/ansible
  ansible collection location = /Users/lmerg/code
  executable location = /Users/lmerg/.pyenv/versions/cluster/bin/ansible
  python version = 3.9.5 (default, May 25 2021, 17:35:37) [Clang 11.0.0 (clang-1100.0.33.16)]
  jinja version = 3.0.1
  libyaml = True
COLLECTION VERSION
 /Users/lmerg/code/ansible_collections
Collection           Version
-------------------- -------
community.docker     1.9.1
CONFIGURATION
ANSIBLE_NOCOWS(/Users/lmerg/code/cluster/ansible.cfg) = True
CACHE_PLUGIN(/Users/lmerg/code/cluster/ansible.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(/Users/lmerg/code/cluster/ansible.cfg) = /tmp/ansible_facts_cache
COLLECTIONS_PATHS(/Users/lmerg/code/cluster/ansible.cfg) = ['/Users/lmerg/code']
DEFAULT_GATHERING(/Users/lmerg/code/cluster/ansible.cfg) = smart
DEFAULT_HOST_LIST(/Users/lmerg/code/cluster/ansible.cfg) = ['/Users/lmerg/code/cluster/hosts.ini']
DEFAULT_VAULT_PASSWORD_FILE(env: ANSIBLE_VAULT_PASSWORD_FILE) = /Users/lmerg/code/cluster/.vault_pass
HOST_KEY_CHECKING(/Users/lmerg/code/cluster/ansible.cfg) = False
OS / ENVIRONMENT

Darwin mergner-air 19.6.0 Darwin Kernel Version 19.6.0: Mon Apr 12 20:57:45 PDT 2021; root:xnu-6153.141.28.1~1/RELEASE_X86_64 x86_64

STEPS TO REPRODUCE

Here is an example which requires plugin_options, but even the docker docs use sshfs which could take DEBUG=1 option

- name: Docker (install glusterfs plugin)
  community.docker.docker_plugin:
    plugin_name: marcelo-ochoa/glusterfs-volume-plugin:latest
    state: present
    alias: glusterfs
    plugin_options:
      SERVERS: "{{ groups['cluster'] | map('extract', hostvars, 'ansible_hostname') | map('join', '.lan') }}"
EXPECTED RESULTS
  1. Expected to skip configuring a plugin if installed.
  2. or, Expected that I'd be able to get information about plugins before trying to install with configuration options.
ACTUAL RESULTS
TASK [lmergner.mergnet.docker : Docker (install glusterfs plugin)] *********************
fatal: [mergnas]: FAILED! => {"changed": false, "msg": "500 Server Error for http+docker://localhost/v1.41/plugins/glusterfs:latest/set: Internal Server Error (\"cannot set on an active plugin, disable plugin before setting\")"}
felixfontein commented 3 years ago

docker plugin throws an error when it tries to set an activated plugin. If a plugin already exists, but you have plugin_options: {<options>} in the task, it will fail instead of modifying the plugin.

I'm not sure whether it should dis- and then afterwards re-enable the plugin in this case (or allow to configure that behavior), or just fail more gracefully. (I don't use Docker plugins myself.)

Being able to configure this behavior (potentially three options: a) fail, b) just don't configure, c) disable, configure, and then re-enable) is probably the best thing (with whatever default makes most sense for plugins in general). If you're interested in implementing this, feel free to submit a PR!

It's also unclear from the docs whether I need to install (state: present) before I enable (state: enabled) a plugin using ansible. If I enable it, does the module also install it?

If you enable it and it is not installed, it first installs it and then enables it: https://github.com/ansible-collections/community.docker/blob/f01dacd6cf87912a418248e6e7ff640f066d23d6/plugins/modules/docker_plugin.py#L309-L316

This might be a reason to have a docker_plugin_info since, using ansible, I cannot read docker plugin ls — and docker_host_info does not include a section for plugins.

That would be nice indeed. If you want to contribute such a module, or extend docker_host_info to return that information, PRs are welcome.

x2764tech commented 3 years ago

@felixfontein My issue is that it doesn't check to see whether the plugin settings need to be be changed - so it'll work the first time, and then fail on subsequent runs as it's unnecessarily trying to update the settings on an active plugin. I think I'd need a different play for updating a plugin settings, as it's not always possible to disable a plugin - it's very possible it's in use, so I'd need to scale down the services referencing it, and then disable it, update the setting, and then scale up the services again... not as trivial as you think

enpaul commented 3 months ago

Adding on to this report, I'm experiencing a similar issue (ironically with the same plugin). I dynamically generate the plugin settings at runtime based on my inventory, thus changing my inventory changes the settings of the plugin. When I run this module, it does not update the settings of the plugin but instead of erroring or warning it reports no changes. I'm not sure what the proper behavior should be in this case, but silencing this desired diff seems unideal.


Example scenario and code:

# inventory_1.yaml
storage:
  hosts:
    data01:
    data02:
# inventory_2.yaml
storage:
  hosts:
    data01:
    data02:
    data03:
# playbook.yml
- name: Configure storage pool
  hosts: storage
  tasks:
  - name: Install glusterfs plugin
    community.docker.docker_plugin:
      alias: "storage"
      plugin_name: docker.io/mochoa/glusterfs-volume-plugin
      state: enable
      plugin_options:
        SERVERS: "{{ groups['storage'] | join(',') }}"

Running ansible-playbook playbook.yml -i inventory_1.yaml results in no errors and hosts data01 and data02 being configured with 'SERVERS':'data01,data02'.

Then running ansible-playbook playbook.yml -i inventory_2.yaml also results in no errors, but data01 and data02 are still configured with 'SERVERS':'data01,data02' and data03 is configured with 'SERVERS':'data01,data02,data03'. I would expect some indication from this module that either an update needs to occur but is not possible or that the current state at least does not match the desired state.

felixfontein commented 3 months ago

Hmm, this looks more like a problem with the docker.io/mochoa/glusterfs-volume-plugin plugin to me. Apparently the module was able to tell the plugin to update, since data03 is there and has the new value, but the plugin didn't update data01 and data02.

The module does not know anything about what the plugin does, so it has to rely on the plugin to correctly update its state somehow.