haxorof/ansible-role-docker-ce

Issues upgrading already installed plugins

janorn opened this issue · 8 comments

Version Information

Ansible: 2.9.27
Role: 3.7.0

Steps to Reproduce

First install docker with this config:

docker_plugins:
  - type: authz
    alias: opa-docker-authz
    name: openpolicyagent/opa-docker-authz-v2:0.4
    args: opa-args="-policy-file /opa/policy/authz.rego -quiet"

Second re run role but with upgraded plugin.

docker_plugins:
  - type: authz
    alias: opa-docker-authz
    name: openpolicyagent/opa-docker-authz-v2:0.8
    args: opa-args="-policy-file /opa/policy/authz.rego -quiet"

Expected Behavior

Latest version of plugin to be installed.

Actual Behavior

No change.

Before and after this command gives the same output:

# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@pkrvmmotjxu12cl ~]# docker plugin ls
ID             NAME                      DESCRIPTION                                     ENABLED
d545a1e09604   opa-docker-authz:latest   A policy-enabled authorization plugin for Do…   true

Close inspection of the plugin after second run show this:

# docker inspect d545a1e09604
...
        "Name": "opa-docker-authz:latest",
        "PluginReference": "docker.io/openpolicyagent/opa-docker-authz-v2:0.4",
        "Settings": {
            "Args": [
                "-policy-file",
                "/opa/policy/authz.rego"
            ],
            "Devices": [],
            "Env": [],
            "Mounts": [
                {
                    "Description": "",
                    "Destination": "/opa",
                    "Name": "policy",
                    "Options": [
                        "bind",
                        "ro"
                    ],
                    "Settable": [
                        "source"
                    ],
                    "Source": "/etc/docker",
                    "Type": "none"
                }
            ]
        }
...

References

Doing some further testing I removed the alias.

First run:

# docker plugin ls
ID             NAME                                      DESCRIPTION                                     ENABLED
f3d8d5524631   openpolicyagent/opa-docker-authz-v2:0.4   A policy-enabled authorization plugin for Do…   true

Second run:

# docker plugin ls
ID             NAME                                      DESCRIPTION                                     ENABLED
f3d8d5524631   openpolicyagent/opa-docker-authz-v2:0.4   A policy-enabled authorization plugin for Do…   true
4a972a580a5d   openpolicyagent/opa-docker-authz-v2:0.8   A policy-enabled authorization plugin for Do…   true

Only the latest plugin was referenced in the daemon.json config.

Then I did a test on the original setup. But running the install manually but same command as in the role.

# docker plugin install --grant-all-permissions --alias opa-docker-authz openpolicyagent/opa-docker-authz-v2:0.8 opa-args="-policy-file /opa/policy/authz.rego" && echo 'installed'
Error response from daemon: plugin opa-docker-authz:latest already exists

For starters you probably should try to pick up that error.

set -o pipefail

However trying to upgrade the plugins manually I noticed that it is tricky. They have to be disabled to be able to remove them.
Perhaps one could have a cleanup process after but then we need to know what was before. I have no good suggestions yet.
I will probably in my case skip alias and make a list of old plugins and add a post-task to remove the old plugins.

Perhaps listing the installed plugins.

# docker plugin ls --format "{{.Name}}\t{{.Enabled}}"
opa-docker-authz:latest true

And disabling them and then run.

# docker plugin upgrade 

However it seems like the upgrade command lacks alias so might not be a viable solution.

Thanks for reporting this!
The support in this role for installing plug-ins was a best effort implementation to start with. This because already from the beginning it was a bit complex to do the install since it was not made for automation.

Based on what you have tested related to upgrading plug-ins it seems even more difficult and may increase the role complexity too much.

I have to think about this if there are something that can be done. I will also test the upgrade using the test I have for installing plug-ins.

I have found a workaround for my playbook. To make this work I change the plugin alias slightly. As it is in the example you don't assign a version which lead docker to assign ":latest" to it. For my workaround I have decided to have an incremental version on the alias. This will make it possible to both upgrade plugin and also do changes to the plugin config.

docker_plugins:
  - type: authz
    alias: opa-docker-authz:20220322
    name: openpolicyagent/opa-docker-authz-v2:0.8
    args: opa-args="-policy-file /opa/policy/authz.rego -quiet"

Then adding the following tasks to the playbook after the role has executed removes all plugins not listed in docker_plugins.

- name: List installed plugins
  become: true
  command: "docker plugin ls --format={%raw%}'{{json .}}'{%endraw%}"
  register: plugins

- name: Assemble installed plugin list
  set_fact:
    installed_plugins: "{{ installed_plugins | default([]) | union([item | from_json]) }}"
  loop: "{{ plugins.stdout.split('\n') }}"

- name: Find which plugins to remove
  set_fact:
    old_plugins: "{{ old_plugins | default([]) | union(installed_plugins | selectattr('Name', 'equalto', item)|list) }}"
  loop: "{{ (installed_plugins|map(attribute='Name'))|difference(docker_plugins|map(attribute='alias'))|list }}"

- name: Disable old plugins
  become: true
  command: "docker plugin disable {{ item.Name }}"
  when: item.Enabled
  loop: "{{ old_plugins | default([]) }}"

- name: Remove old plugins
  become: true
  command: "docker plugin rm {{ item.Name }}"
  loop: "{{ old_plugins | default([]) }}"

Won't fix this in the role. Closing issue.