diff --git a/runon.default.yaml b/runon.default.yaml index 85e149c..b96ec82 100644 --- a/runon.default.yaml +++ b/runon.default.yaml @@ -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 diff --git a/runon/runon.py b/runon/runon.py index 89ade43..e67084e 100755 --- a/runon/runon.py +++ b/runon/runon.py @@ -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 diff --git a/setup.py b/setup.py index 0dc9b23..dc7da5a 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,6 @@ setup( packages = find_packages(), python_requires = ">=3.6", install_requires = [ - "docker", - "dockerpty", "pathlib", "pyxdg", "pyyaml",