Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
*.egg-info
build/
dist/
venv/
.venv/
.*swp
pyinfra-debug.log

.vagrant*

example/ssh_config

.pytest_cache
__pycache__
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

A basic [pyinfra](https://pyinfra.com) deploy that installs and optionally configures Docker on the target hosts. Officially tested & supported Linux distributions:

+ Ubuntu 16/18/20
+ Debian 8/9/10
+ CentOS 7/8
+ Ubuntu 24.04
+ Debian 12
+ Alma Linux 9
+ Fedora 41

This deploy installs packages in the `docker-ce` ecosystem (`docker-ce`/`docker-ce-cli`/`docker-ce-rootless-extras`) You can specify `docker_version` in the host data and it will install that version for all `docker-ce` packages.

Expand Down
28 changes: 8 additions & 20 deletions example/Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,19 @@ Vagrant.configure('2') do |config|
# Disable /vagrant synced folder
config.vm.synced_folder '.', '/vagrant', disabled: true

config.vm.define :ubuntu16 do |ubuntu|
ubuntu.vm.box = 'bento/ubuntu-16.04'
config.vm.define :debian12 do |debian|
debian.vm.box = 'debian/bookworm64'
end

config.vm.define :ubuntu18 do |ubuntu|
ubuntu.vm.box = 'bento/ubuntu-18.04'
config.vm.define :ubuntu2404 do |ubuntu|
ubuntu.vm.box = 'bento/ubuntu-24.04'
end

config.vm.define :ubuntu20 do |ubuntu|
ubuntu.vm.box = 'bento/ubuntu-20.04'
config.vm.define :fedora41 do |fedora|
fedora.vm.box = 'bento/fedora-41'
end

config.vm.define :debian9 do |debian|
debian.vm.box = 'bento/debian-9.11'
end

config.vm.define :debian10 do |debian|
debian.vm.box = 'bento/debian-10'
end

config.vm.define :centos7 do |centos|
centos.vm.box = 'bento/centos-7'
end

config.vm.define :almalinux8 do |almalinux|
almalinux.vm.box = 'bento/almalinux-8'
config.vm.define :almalinux9 do |almalinux|
almalinux.vm.box = 'almalinux/9'
end
end
4 changes: 1 addition & 3 deletions example/deploy.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
from pyinfra import config
from pyinfra.context import config
from pyinfra.operations import server

from pyinfra_docker import deploy_docker

config.SUDO = True


deploy_docker(
config={
"dns": ["8.8.8.8", "8.8.4.4"],
"debug": True,
},
)


server.service(
name="Ensure docker service is running",
service="docker",
Expand Down
11 changes: 4 additions & 7 deletions example/tests.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
testinfra_hosts = [
"ssh://ubuntu16",
"ssh://ubuntu18",
"ssh://ubuntu20",
"ssh://debian9",
"ssh://debian10",
"ssh://centos7",
"ssh://almalinux8",
"ssh://ubuntu2404",
"ssh://debian12",
"ssh://almalinux9",
"ssh://fedora41"
]


Expand Down
1,272 changes: 1,272 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions poetry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[virtualenvs]
in-project = true
88 changes: 48 additions & 40 deletions pyinfra_docker/docker.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import json
from io import StringIO

from pyinfra import host
from pyinfra.context import host
from pyinfra.api.deploy import deploy
from pyinfra.api.exceptions import DeployError
from pyinfra.api.util import make_hash
from pyinfra.facts.deb import DebPackages
from pyinfra.facts.rpm import RpmPackages
from pyinfra.facts.server import Command, LinuxDistribution, LsbRelease, Which
from pyinfra.operations import apt, dnf, files, yum
from pyinfra.facts.server import Command, LinuxName, LsbRelease, Which
from pyinfra.operations import apt, dnf, files


DEFAULTS = {
Expand All @@ -21,66 +19,80 @@ def get_pkgs_to_install(operator):
"docker-ce",
"docker-ce-cli",
"docker-ce-rootless-extras",
"docker-compose-plugin"
]
if not host.data.docker_version:
return docker_packages

return [f"{pkg}{operator}{host.data.docker_version}" for pkg in docker_packages]



def _apt_install(packages):
apt.packages(
name="Install apt requirements to use HTTPS",
packages=["apt-transport-https", "ca-certificates"],
name="Install Script Dependencies",
packages=["apt-transport-https", "ca-certificates", "curl", "gnupg", "lsb-release"],
update=True,
cache_time=3600,
)

lsb_release = host.get_fact(LsbRelease)
lsb_id = lsb_release["id"].lower()

apt.key(
name="Download the Docker apt key",
src="https://download.docker.com/linux/{0}/gpg".format(lsb_id),
keyringPath = "/etc/apt/keyrings"
gpgKeyPath = f"{keyringPath}/docker.asc"

files.directory(
name="Ensure Keyrings Directory Exists",
path=keyringPath,
present=True,
mode="0755",
force=True,
)

files.download(
name="Download GPG Key",
src=f"https://download.docker.com/linux/{lsb_id}/gpg",
dest=gpgKeyPath,
)

dpkg_arch = host.get_fact(Command, command="dpkg --print-architecture")

add_apt_repo = apt.repo(
name="Add the Docker apt repo",
name="Add the Docker APT repo",
src=(
f"deb [arch={dpkg_arch}] https://download.docker.com/linux/{lsb_id}"
f"deb [arch={dpkg_arch} signed-by={gpgKeyPath}] https://download.docker.com/linux/{lsb_id}"
f" {lsb_release['codename']} stable"
),
filename="docker-ce-stable",
filename="docker",
)

apt.packages(
name="Install Docker via apt",
name="Install Docker via APT",
packages=packages,
update=add_apt_repo.changed, # update if we added the repo
allow_downgrades=True,
)


def _yum_or_dnf_install(yum_or_dnf, packages):
yum_or_dnf.repo(
name="Add the Docker yum repo",
src="https://download.docker.com/linux/centos/docker-ce.repo",
)
def _dnf_install(packages):
linuxName = host.get_fact(LinuxName).lower()

# Installing Docker on CentOS 8 is currently broken and requires this hack
# See: https://github.com/docker/for-linux/issues/873
extra_install_args = ""
linux_distro = host.get_fact(LinuxDistribution)
if linux_distro["name"] == "CentOS" and linux_distro["major"] == 8:
extra_install_args = "--nobest"
osOverrides = {"almalinux": "rhel"}

yum_or_dnf.packages(
name="Install Docker via yum",
if linuxName in osOverrides:
linuxName = osOverrides[linuxName]

add_dnf_repo = dnf.repo(
name="Add the Docker DNF repo",
src=f"https://download.docker.com/linux/{linuxName}/docker-ce.repo",
present=True,
)

dnf.packages(
name="Install Docker via DNF",
packages=packages,
extra_install_args=extra_install_args,
present=True,
update=add_dnf_repo.changed,
)


Expand All @@ -92,21 +104,17 @@ def deploy_docker(config=None):
Args:
config: filename or dict of JSON data
"""

if host.get_fact(DebPackages):
packages = get_pkgs_to_install('=')
if host.get_fact(Which, command="apt") is not None:
packages = get_pkgs_to_install("=")
_apt_install(packages)
elif host.get_fact(RpmPackages):
packages = get_pkgs_to_install('-')
_yum_or_dnf_install(
dnf if host.get_fact(Which, command="dnf") else yum,
packages,
)
elif host.get_fact(Which, command="dnf") is not None:
packages = get_pkgs_to_install("-")
_dnf_install(packages)
else:
raise DeployError(
(
"Neither apt or yum were found, "
"pyinfra-docker cannot provision this machine!"
"Neither apt or dnf were found, "
f"pyinfra-docker cannot provision this machine! {host.name}"
),
)

Expand Down
27 changes: 27 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[project]
name = "pyinfra-docker"
version = "3.0.0"
description = "Install & configure Docker with `pyinfra`."
authors = [
{name = "Nick Fizzadar", email = "nick@fizzadar.com"}
]
maintainers = [
{name = "David Kovari", email = "david@kovari.io"}
]
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"pyinfra (>=3.2,<4.0)"
]
license = "MIT"

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.group.dev.dependencies]
black = "^25.1.0"

[tool.poetry.group.test.dependencies]
pytest = "^8.3.5"
pytest-testinfra = "^10.2.2"
5 changes: 0 additions & 5 deletions setup.cfg

This file was deleted.

36 changes: 0 additions & 36 deletions setup.py

This file was deleted.