Skip to content

Commit

Permalink
fix: add docker_image plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
ricolin committed Nov 17, 2023
1 parent db19b06 commit b264a8b
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 1 deletion.
122 changes: 122 additions & 0 deletions plugins/filter/docker_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import, division, print_function

__metaclass__ = type

from ansible.errors import AnsibleFilterError
from ansible.module_utils.common.collections import is_string

try:
from docker_image import reference

HAS_DOCKER_IMAGE = True
except ImportError:
HAS_DOCKER_IMAGE = False

DOCUMENTATION = """
name: docker_image
short_description: Parse a Docker image reference
version_added: 0.13.0
description:
- Parse a Docker image and return different parts of the reference
- This lookup module requires "docker-image-py" to be installed on the
Ansible controller.
options:
_input:
type: string
required: true
description:
- Docker image reference to parse
part:
type: string
default: 'ref'
options: [name, ref, tag, domain, path]
required: true
description:
- Part of the Docker image reference to return
registry:
type: string
required: false
description:
- Override the registry in the Docker image reference
author:
- Mohammed Naser <mnaser@vexxhost.com>
"""

EXAMPLES = """
- name: Generate a Docker image reference
ansible.builtin.debug:
msg: "{{ 'docker.io/library/memcached:1.6.3' | vexxhost.kubernetes.docker_image('name') }}"
"""

RETURN = """
_value:
description: The part of the Docker image reference
type: string
"""


def docker_image(value, part="ref", registry=None):
if not is_string(value):
raise AnsibleFilterError(
"Invalid value type (%s) for docker_image (%r)" % (type(value), value)
)

if not HAS_DOCKER_IMAGE:
raise AnsibleFilterError(
"Failed to import docker-image-py module, ensure it is installed on the controller"
)

def _lookup_part(ref, part):
if part == "ref":
return ref.string()
if part == "name":
return ref["name"]
if part == "tag":
return ref["tag"]
if part == "domain":
return ref.repository["domain"]
if part == "path":
return ref.repository["path"]
if part == "digest":
return ref["digest"]
if part == "prefix":
path_parts = ref.repository["path"].split("/")[:-1]
parts = [ref.repository["domain"]] + path_parts
return "/".join(parts)

ref = reference.Reference.parse(value)
if not registry:
return _lookup_part(ref, part)

# NOTE(mnaser): We re-write the name of a few images to make sense of them
# in the context of the override registry.
ref_name = ref.repository["path"].split("/")[-1]
if value == "skopeo":
ref_name = "skopeo-stable"

# NOTE(mnaser): Since the attributes inside of reference.Reference are not
# determined during parse time, we need to re-parse the
# string to get the correct attributes.
ref["name"] = "{}/{}".format(registry, ref_name)
ref = reference.Reference.parse(ref.string())

return _lookup_part(ref, part)


class FilterModule(object):
def filters(self):
return {"docker_image": docker_image}
2 changes: 1 addition & 1 deletion roles/containerd/templates/config.toml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ oom_score = {{ containerd_oom_score }}

[plugins]
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "{{ containerd_pause_image | vexxhost.kubernetes.docker_image('ref') }}"
sandbox_image = "{{ containerd_pause_image | vexxhost.containers.docker_image('ref') }}"
max_container_log_line_size = {{ containerd_max_container_log_line_size }}
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
Expand Down
137 changes: 137 additions & 0 deletions tests/unit/plugins/filter/test_docker_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import pytest
from ansible_collections.vexxhost.containers.plugins.filter.docker_image import (
docker_image,
)


@pytest.mark.parametrize(
"test_input,expected",
[
("quay.io/vexxhost/glance:zed", "quay.io/vexxhost/glance:zed"),
(
"us-docker.pkg.dev/vexxhost-infra/openstack/heat:wallaby",
"us-docker.pkg.dev/vexxhost-infra/openstack/heat:wallaby",
),
(
"k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0",
"k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0",
),
("docker.io/library/haproxy:2.5", "docker.io/library/haproxy:2.5"),
(
"k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de", # noqa E501
"k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de", # noqa E501
),
],
)
def test_docker_image_ref(test_input, expected):
assert docker_image(test_input, "ref") == expected


@pytest.mark.parametrize(
"test_input,expected",
[
("quay.io/vexxhost/glance:zed", "quay.io/vexxhost/glance"),
(
"us-docker.pkg.dev/vexxhost-infra/openstack/heat:wallaby",
"us-docker.pkg.dev/vexxhost-infra/openstack/heat",
),
(
"k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0",
"k8s.gcr.io/sig-storage/csi-snapshotter",
),
("docker.io/library/haproxy:2.5", "docker.io/library/haproxy"),
(
"k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de", # noqa E501
"k8s.gcr.io/ingress-nginx/controller",
),
],
)
def test_docker_image_name(test_input, expected):
assert docker_image(test_input, "name") == expected


@pytest.mark.parametrize(
"test_input,expected",
[
("quay.io/vexxhost/glance:zed", "quay.io"),
(
"us-docker.pkg.dev/vexxhost-infra/openstack/heat:wallaby",
"us-docker.pkg.dev",
),
(
"k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0",
"k8s.gcr.io",
),
("docker.io/library/haproxy:2.5", "docker.io"),
(
"k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de", # noqa E501
"k8s.gcr.io",
),
],
)
def test_docker_image_domain(test_input, expected):
assert docker_image(test_input, "domain") == expected


@pytest.mark.parametrize(
"test_input,expected",
[
("quay.io/vexxhost/glance:zed", "vexxhost/glance"),
(
"us-docker.pkg.dev/vexxhost-infra/openstack/heat:wallaby",
"vexxhost-infra/openstack/heat",
),
(
"k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0",
"sig-storage/csi-snapshotter",
),
("docker.io/library/haproxy:2.5", "library/haproxy"),
(
"k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de", # noqa E501
"ingress-nginx/controller",
),
],
)
def test_docker_image_path(test_input, expected):
assert docker_image(test_input, "path") == expected


@pytest.mark.parametrize(
"test_input,expected",
[
("quay.io/vexxhost/glance:zed", "quay.io/vexxhost"),
(
"us-docker.pkg.dev/vexxhost-infra/openstack/heat:wallaby",
"us-docker.pkg.dev/vexxhost-infra/openstack",
),
(
"registry.k8s.io/kube-apiserver:v1.22.0",
"registry.k8s.io",
),
(
"k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0",
"k8s.gcr.io/sig-storage",
),
("docker.io/library/haproxy:2.5", "docker.io/library"),
(
"k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de", # noqa E501
"k8s.gcr.io/ingress-nginx",
),
],
)
def test_docker_image_prefix(test_input, expected):
assert docker_image(test_input, "prefix") == expected

0 comments on commit b264a8b

Please sign in to comment.