convert to podman

* call podman exec instead of using API:
  - build does not support progress
  - run looks like to lack equivalent dockerpty support
* config: use full uri as short names are not supported on
  all OSes (like debian 11)
This commit is contained in:
Gilles Grandou 2023-12-05 00:02:15 +01:00
parent bd6a026e9c
commit e0b228799f
3 changed files with 78 additions and 111 deletions

View File

@ -21,9 +21,6 @@ debian_base: &debian_base
binds:
- /etc/timezone:ro
- /etc/localtime:ro
- /etc/passwd:ro
- /etc/group:ro
- /etc/shadow:ro
- "{home}"
environment:
- USER
@ -33,7 +30,7 @@ debian_base: &debian_base
debian9:
<<: *debian_base
image: debian:9
image: docker.io/debian:9
dockerfile:
- ARG DEBIAN_FRONTEND=noninteractive
- RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list
@ -46,23 +43,24 @@ debian9:
debian10:
<<: *debian_base
image: debian:10
image: docker.io/debian:10
debian11:
<<: *debian_base
image: debian:11
image: docker.io/debian:11
debian12:
<<: *debian_base
image: debian:12
image: docker.io/debian:12
ubuntu20.04:
<<: *debian_base
image: ubuntu:20.04
image: docker.io/ubuntu:20.04
ubuntu22.04:
<<: *debian_base
image: ubuntu:22.04
image: docker.io/ubuntu:22.04
rh_base: &rh_base
dockerfile:
- RUN dnf install -y sudo
@ -80,9 +78,6 @@ rh_base: &rh_base
binds:
- /etc/timezone:ro
- /etc/localtime:ro
- /etc/passwd:ro
- /etc/group:ro
- /etc/shadow:ro
- "{home}"
environment:
- USER
@ -93,7 +88,7 @@ rh_base: &rh_base
centos7:
<<: *rh_base
image: centos:7
image: docker.io/centos:7
dockerfile:
- RUN yum install -y sudo
- RUN echo "Defaults lecture = never" >> /etc/sudoers
@ -104,9 +99,9 @@ centos7:
rocky8:
<<: *rh_base
image: rockylinux:8
image: docker.io/rockylinux:8
rocky9:
<<: *rh_base
image: rockylinux:9
image: docker.io/rockylinux:9

View File

@ -1,13 +1,8 @@
import sys
import os
import argparse
import docker
import dockerpty
import io
import getpass
import pathlib
import platform
import os
import re
import xdg.BaseDirectory
import yaml
import datetime
@ -80,16 +75,10 @@ def make_osname_link(binpath, osname):
except FileExistsError:
pass
def make_image_name(osname):
user = getpass.getuser()
name = 'runon-{}-{}'.format(osname, user)
return name
def build_image(client, conf, update, verbose):
def build_image(conf, update, verbose):
osname = conf.get('osname')
image_name = 'runon-{}'.format(osname)
tag = make_image_name(conf['osname'])
cache_dir = os.path.join(xdg.BaseDirectory.xdg_cache_home, 'runon')
cache_file = os.path.join(cache_dir, image_name)
@ -102,92 +91,80 @@ def build_image(client, conf, update, verbose):
if ts_image and ts_image > ts_conf:
if verbose:
print('image: {} up-to-date'.format(image_name))
image = client.images.get(tag)
return image
return image_name
image = conf.get('image')
packages = conf['packages']
dockerfile = conf['dockerfile']
pkginstall = conf['pkginstall']
dockerfile = conf.get('dockerfile')
pkginstall = conf.get('pkginstall')
packages = conf.get('packages')
if not dockerfile:
dockerfile = []
if image:
dockerfile.insert(0, 'FROM {}'.format(image))
for p in packages:
dockerfile.append(pkginstall.format(p))
try:
if packages:
for p in packages:
dockerfile.append(pkginstall.format(p))
if verbose:
print('Dockerfile:')
for l in dockerfile:
print(' * {}'.format(l))
print('Building image {} ...'.format(image_name))
cmd = ['podman', 'build']
if update:
cmd.append('--no-cache')
cmd += ['-t', image_name, '-']
ret = subprocess.run(cmd,
input='\n'.join(dockerfile).encode('utf-8'),
stderr=subprocess.STDOUT, check=True)
if not os.path.exists(cache_dir):
os.mkdir(cache_dir)
with open(cache_file, 'w') as file:
if verbose:
print('Building image {} ...'.format(tag))
cmd = ['docker', 'build']
if update:
cmd.append('--no-cache')
cmd += ['-t', tag, '-']
ret = subprocess.run(cmd,
input='\n'.join(dockerfile).encode('utf-8'),
stderr=subprocess.STDOUT, check=True)
image = client.images.get(tag)
print('cache: {}'.format(cache_file))
file.write('')
if not os.path.exists(cache_dir):
os.mkdir(cache_dir)
with open(cache_file, 'w') as file:
if verbose:
print('cache: {}'.format(cache_file))
file.write('')
except (docker.errors.BuildError, KeyboardInterrupt, subprocess.CalledProcessError, docker.errors.ImageNotFound) as e:
print('Build Error: {}'.format(e))
print()
print('with dockerfile:')
for line in dockerfile:
print(' {}'.format(line))
sys.exit(1)
return image
return image_name
def create_container(client, image, conf, command, verbose):
volumes = {}
def run_image(name, conf, command, verbose):
volumes = {
}
environment = {}
for mnt in conf['binds']:
mnt = mnt.split(':')
if mnt[-1] in ['ro','rw']:
mode = mnt[-1]
del mnt[-1]
else:
mode = 'rw'
mnt = mnt[:2]
bind = mnt[-1]
vol = mnt[0]
volumes[vol] = { 'bind': bind, 'mode': mode }
hostname = platform.node()
for v in conf['environment']:
e = v.split('=')
if len(e) == 1:
e.append(os.getenv(e[0]))
environment[e[0]] = e[1]
#environment['debian_chroot']=conf['osname']
user='{}:{}'.format(os.getuid(), os.getgid())
pwd=os.getcwd()
if conf.get('binds'):
for mnt in conf['binds']:
mnt = mnt.split(':')
if mnt[-1] in ['ro','rw']:
mode = mnt[-1]
del mnt[-1]
else:
mode = 'rw'
mnt = mnt[:2]
bind = mnt[-1]
vol = mnt[0]
if os.path.exists(vol):
volumes[vol] = { 'bind': bind, 'mode': mode }
if conf.get('environment'):
for v in conf['environment']:
e = v.split('=')
if len(e) == 1:
e.append(os.getenv(e[0]))
environment[e[0]] = e[1]
container = client.containers.create(image, command,
detach=False, stdin_open=True, tty=True,
auto_remove=True,
hostname=hostname,
volumes=volumes,
environment=environment,
user=user,
network_mode='host',
working_dir=pwd
)
return container
def run_container(client, container):
try:
dockerpty.start(client.api, container.id)
container.reload() # to update attrs fields
except docker.errors.APIError as e:
print('ERROR: {}'.format(e))
sys.exit(1)
ret = container.attrs['State']['ExitCode']
return ret
cmd = ['podman', 'run', '--rm', '--interactive', '--tty', '--userns=keep-id', '--net=host' ]
for e in environment:
cmd += [ '-e', '{}={}'.format(e, environment[e]) ]
for v in volumes:
cmd += [ '-v', ':'.join([v, volumes[v]['bind'], volumes[v]['mode']]) ]
cmd += [ '--workdir', os.getcwd() ]
cmd += [ name ]
if command:
cmd += command
if verbose:
print('executing: {}\n'.format(' '.join(cmd)))
ret = subprocess.run(cmd)
return ret.returncode
def main():
@ -247,10 +224,7 @@ def main():
make_osname_link(sys.argv[0], args.osname)
conf = load_config(conf_file, args.osname)
client = docker.from_env()
image = build_image(client, conf, args.update, args.verbose)
container = create_container(client, image, conf, args.command, args.verbose)
ret = run_container(client, container)
image_name = build_image(conf, args.update, args.verbose)
ret = run_image(image_name, conf, args.command, args.verbose)
return ret

View File

@ -9,8 +9,6 @@ setup(
packages = find_packages(),
python_requires = ">=3.6",
install_requires = [
"docker",
"dockerpty",
"pathlib",
"pyxdg",
"pyyaml",