From 8ccd734c023b92f56a419d05972f407980939bea Mon Sep 17 00:00:00 2001 From: Gilles Grandou Date: Mon, 4 Dec 2023 22:39:30 +0100 Subject: [PATCH] moved config format from INI to YAML --- install | 4 +- runon.default.conf | 121 --------------------------------------------- runon.default.yaml | 116 +++++++++++++++++++++++++++++++++++++++++++ runon/runon.py | 110 ++++++++++++++++++++++++----------------- setup.py | 3 +- uninstall | 2 +- 6 files changed, 185 insertions(+), 171 deletions(-) delete mode 100644 runon.default.conf create mode 100644 runon.default.yaml diff --git a/install b/install index d042ae0..93c90a0 100755 --- a/install +++ b/install @@ -28,9 +28,9 @@ ln -sf $venvdir/bin/runon $bindir/ echo "install base config in $configdir..." mkdir -p $configdir if [ -n "$devmode" ]; then - ln -s $srcdir/runon.default.conf $configdir/ + ln -s $srcdir/runon.default.yaml $configdir/ else - cp -p $srcdir/runon.default.conf $configdir/ + cp -p $srcdir/runon.default.yaml $configdir/ fi echo "done." diff --git a/runon.default.conf b/runon.default.conf deleted file mode 100644 index b6d9a0d..0000000 --- a/runon.default.conf +++ /dev/null @@ -1,121 +0,0 @@ -[DEFAULT] -environment = - HOME - USER - DISPLAY - TERM - debian_chroot=${osname} - -binds = - /etc/timezone:ro - /etc/localtime:ro - /etc/passwd:ro - /etc/group:ro - /etc/shadow:ro - /tmp/.X11-unix:ro - /home/${user} - -[centos7] -dockerfile = - FROM centos:7 - RUN yum install sudo -y - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers - RUN yum group install -y "Development Tools" -pkginstall = RUN yum install {} -y -packages = xterm vim-X11 git python3 bash-completion - -[rocky8] -dockerfile = - FROM rockylinux:8 - RUN yum install sudo -y - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN yum install {} -y -packages = xterm vim-X11 git python3 bash-completion - -[rocky9] -dockerfile = - FROM rockylinux:9 - RUN dnf install sudo -y - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN dnf install {} -y -packages = xterm vim-X11 git python3 bash-completion - -[debian9] -dockerfile = - FROM debian:9 - ARG DEBIAN_FRONTEND=noninteractive - RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list - RUN apt-get update - RUN apt-get -y upgrade - RUN apt install -y --allow-downgrades libnettle6=3.3-1+b2 # default libnettle6 conflicts with libgtk-3.0 - RUN apt-get -y install sudo - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN apt-get -y install {} -packages = xterm x11-apps vim-gtk3 git build-essential python3 bash-completion - -[debian10] -dockerfile = - FROM debian:10 - ARG DEBIAN_FRONTEND=noninteractive - RUN apt-get update - RUN apt-get -y install apt-utils - RUN apt-get -y upgrade - RUN apt-get -y install sudo - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN apt-get -y install {} -packages = xterm x11-apps vim-gtk3 git build-essential python3 bash-completion - -[debian11] -dockerfile = - FROM debian:11 - ARG DEBIAN_FRONTEND=noninteractive - RUN apt-get update - RUN apt-get -y install apt-utils - RUN apt-get -y install sudo - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN apt-get -y install {} -packages = xterm x11-apps vim-gtk3 git build-essential python3 bash-completion - -[debian12] -dockerfile = - FROM debian:12 - ARG DEBIAN_FRONTEND=noninteractive - RUN apt-get update - RUN apt-get -y install apt-utils - RUN apt-get -y install sudo - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN apt-get -y install {} -packages = xterm x11-apps vim-gtk3 git build-essential python3 bash-completion - -[ubuntu20.04] -dockerfile = - FROM ubuntu:20.04 - ARG DEBIAN_FRONTEND=noninteractive - RUN apt-get update - RUN apt-get -y install apt-utils - RUN apt-get -y install sudo - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN apt-get -y install {} -packages = xterm x11-apps vim-gtk3 git build-essential python3 bash-completion - - -[ubuntu22.04] -dockerfile = - FROM ubuntu:22.04 - ARG DEBIAN_FRONTEND=noninteractive - RUN apt-get update - RUN apt-get -y install apt-utils - RUN apt-get -y install sudo - RUN echo "Defaults lecture = never" >> /etc/sudoers - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -pkginstall = RUN apt-get -y install {} -packages = xterm x11-apps vim-gtk3 git build-essential python3 bash-completion - diff --git a/runon.default.yaml b/runon.default.yaml new file mode 100644 index 0000000..73281bd --- /dev/null +++ b/runon.default.yaml @@ -0,0 +1,116 @@ + +debian_base: &debian_base + dockerfile: + - ARG DEBIAN_FRONTEND=noninteractive + - RUN apt-get update + - RUN apt-get -y install apt-utils + - RUN apt-get -y upgrade + - RUN apt-get -y install sudo + - RUN echo "Defaults lecture = never" >> /etc/sudoers + - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + pkginstall: + "RUN apt-get -y install {}" + packages: + - xterm + - x11-apps + - vim-gtk3 + - git + - build-essential + - python3 + - bash-completion + binds: + - /etc/timezone:ro + - /etc/localtime:ro + - /etc/passwd:ro + - /etc/group:ro + - /etc/shadow:ro + - /tmp/.X11-unix:ro + - /home/{user} + environment: + - HOME + - USER + - DISPLAY + - TERM + - debian_chroot={osname} + +debian9: + <<: *debian_base + image: debian:9 + dockerfile: + - ARG DEBIAN_FRONTEND=noninteractive + - RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list + - RUN apt-get update + - RUN apt-get -y upgrade + - RUN apt install -y --allow-downgrades libnettle6=3.3-1+b2 # default libnettle6 conflicts with libgtk-3.0 + - RUN apt-get -y install sudo + - RUN echo "Defaults lecture = never" >> /etc/sudoers + - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +debian10: + <<: *debian_base + image: debian:10 + +debian11: + <<: *debian_base + image: debian:11 + +debian12: + <<: *debian_base + image: debian:12 + +ubuntu20.04: + <<: *debian_base + image: ubuntu:20.04 + +ubuntu22.04: + <<: *debian_base + image: ubuntu:22.04 +rh_base: &rh_base + dockerfile: + - RUN dnf install -y sudo + - RUN echo "Defaults lecture = never" >> /etc/sudoers + - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + - RUN dnf group install -y "Development Tools" + pkginstall: + "RUN dnf install -y {}" + packages: + - xterm + - vim-X11 + - git + - python3 + - bash-completion + binds: + - /etc/timezone:ro + - /etc/localtime:ro + - /etc/passwd:ro + - /etc/group:ro + - /etc/shadow:ro + - /tmp/.X11-unix:ro + - /home/{user} + environment: + - HOME + - USER + - DISPLAY + - TERM + - debian_chroot={osname} + + +centos7: + <<: *rh_base + image: centos:7 + dockerfile: + - RUN yum install -y sudo + - RUN echo "Defaults lecture = never" >> /etc/sudoers + - RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + - RUN yum group install -y "Development Tools" + pkginstall: + "RUN yum install -y {}" + +rocky8: + <<: *rh_base + image: rockylinux:8 + +rocky9: + <<: *rh_base + image: rockylinux:9 + diff --git a/runon/runon.py b/runon/runon.py index bc575c8..4b229d7 100755 --- a/runon/runon.py +++ b/runon/runon.py @@ -4,59 +4,70 @@ import docker import dockerpty import io import getpass +import pathlib import platform import os import re import xdg.BaseDirectory -import configparser +import yaml import subprocess from pprint import pprint -def natural_sortkey(string): - tokenize = re.compile(r'(\d+)|(\D+)').findall - return tuple(int(num) if num else alpha for num, alpha in tokenize(string)) +def find_config_file(user_conf): + conf_list = [ + 'runon.yaml', + '.runon.yaml', + os.path.join(xdg.BaseDirectory.xdg_config_home, 'runon', 'runon.yaml'), + os.path.join(xdg.BaseDirectory.xdg_config_home, 'runon', 'runon.default.yaml') + ] + if user_conf: + conf_list = [ user_conf ] + for conf in conf_list: + if os.path.exists(conf): + return conf + return None -def read_ini(user_confname, osname=''): - ini_list = [ - 'runon.conf', - '.runon.conf', - os.path.join(xdg.BaseDirectory.xdg_config_home, 'runon', 'runon.conf'), - os.path.join(xdg.BaseDirectory.xdg_config_home, 'runon', 'runon.default.conf'), - ] - defaults = { - 'osname': osname, - 'user': getpass.getuser() - } - if user_confname: - ini_list.insert(0, user_confname) - ini = configparser.ConfigParser(defaults=defaults, interpolation=configparser.ExtendedInterpolation()) - ini.read(ini_list) - return ini -def list_osnames(user_confname): - ini = read_ini(user_confname) - return ini.sections() - -def load_config(user_confname, osname): - ini = read_ini(user_confname, osname) - if not ini.has_section(osname): - print('ERROR: cannot find configuration for distribution "{}"'.format(osname)) - sys.exit(1) - conf = {} - fields = [ 'dockerfile', 'pkginstall', 'packages', 'environment', 'binds', 'user', 'osname' ] +def read_yaml(conf_file): try: - for f in fields: - conf[f] = ini.get(osname, f) - except configparser.NoOptionError as e: - print('ERROR: {}'.format(e)) + with open(conf_file, 'r') as file: + conf = yaml.safe_load(file) + return conf + except yaml.YAMLError as e: + print(f'ERROR: bad configuration file:') + print(e) sys.exit(1) - for f in [ 'dockerfile', 'environment', 'binds' ]: - conf[f] = [ i for i in conf[f].split('\n') if i ] - for f in [ 'packages' ]: - conf[f] = conf[f].split() return conf +def list_osnames(conf_file): + conf = read_yaml(conf_file) + osnames = [] + for key in conf: + if (type(conf[key]) is dict) and conf[key].get('image'): + osnames.append(key) + return osnames + + +def load_config(conf_file, osname): + user_vars = { + 'osname': osname, + 'user': getpass.getuser(), + 'uid': os.getuid(), + 'home': pathlib.Path.home(), + } + conf = read_yaml(conf_file) + osconf = conf.get(osname) + if not osconf: + print(f"ERROR: cannot find configuration for distribution {osname}") + sys.exit(1) + + osconf['osname'] = osname + for k in [ 'dockerfile', 'packages', 'environment', 'binds' ]: + if osconf.get(k): + osconf[k] = [ s.format(**user_vars) for s in osconf[k]] + return osconf + def make_osname_link(binpath, osname): link = os.path.join(os.path.dirname(binpath), osname) @@ -72,9 +83,12 @@ def make_image_name(osname): def build_image(client, conf, update, verbose): + image = conf.get('image') packages = conf['packages'] dockerfile = conf['dockerfile'] pkginstall = conf['pkginstall'] + if image: + dockerfile.insert(0, 'FROM {}'.format(image)) for p in packages: dockerfile.append(pkginstall.format(p)) tag = make_image_name(conf['osname']) @@ -193,21 +207,25 @@ def main(): if osname: args.osname = osname + conf_file = find_config_file(args.config) + if not conf_file: + print('ERROR: config file not found') + sys.exit(1) + if args.osname == 'list': - osnames = list_osnames(args.config) + osnames = list_osnames(conf_file) print('Available distributions:') - for o in sorted(osnames, key=natural_sortkey): + for o in sorted(osnames): print(' {}'.format(o)) print() - if args.link: - for o in osnames: - make_osname_link(sys.argv[0], args.osname) return 0 - client = docker.from_env() - conf = load_config(args.config, args.osname) if args.link: 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) diff --git a/setup.py b/setup.py index 6d620ff..f5264c9 100644 --- a/setup.py +++ b/setup.py @@ -11,8 +11,9 @@ setup( install_requires = [ "docker", "dockerpty", + "pathlib", "pyxdg", - + "pyyaml", ], entry_points={ "console_scripts": [ diff --git a/uninstall b/uninstall index f38fcff..be5558d 100755 --- a/uninstall +++ b/uninstall @@ -18,7 +18,7 @@ fi if [ -e $configdir ]; then echo "remove configs" - rm -vf $configdir/runon.default.conf + rm -vf $configdir/runon.default.yaml rmdir -v $configdir || true fi