diff --git a/.gitignore b/.gitignore index 72bc9c3c44..f779b62058 100644 --- a/.gitignore +++ b/.gitignore @@ -14,11 +14,16 @@ __pycache__ /docs/osbuild-composer.7 .cache -container_composer_golangci_built.info processed-templates coverage.txt coverage.html - coverage_splunk_logger.txt coverage_splunk_logger.html + +go.local.mod +go.local.sum +container_worker_built.info +container_composer_built.info +container_composer_golangci_built.info + diff --git a/Makefile b/Makefile index 5cce210e64..d5d870227a 100644 --- a/Makefile +++ b/Makefile @@ -169,6 +169,10 @@ clean: rm -rf $(CURDIR)/rpmbuild rm -rf container_composer_golangci_built.info rm -rf $(BUILDDIR)/$(PROCESSED_TEMPLATE_DIR) + rm -rf $(BUILDDIR)/build/ + rm -f $(BUILDDIR)/go.local.* + rm -f $(BUILDDIR)/container_worker_built.info + rm -f $(BUILDDIR)/container_composer_built.info .PHONY: push-check push-check: lint build unit-tests srpm man @@ -326,3 +330,94 @@ $(PROCESSED_TEMPLATE_DIR)/%.yml: $(PROCESSED_TEMPLATE_DIR) $(OPENSHIFT_TEMPLATES .PHONY: process-templates process-templates: $(addprefix $(PROCESSED_TEMPLATE_DIR)/, $(OPENSHIFT_TEMPLATES)) +CONTAINER_EXECUTABLE ?= podman + +CONTAINER_IMAGE_WORKER ?= osbuild-worker_dev +CONTAINERFILE_WORKER := distribution/Dockerfile-worker.dev + +CONTAINER_IMAGE_COMPOSER ?= osbuild-composer_dev +CONTAINERFILE_COMPOSER := distribution/Dockerfile-composer.dev + +GOPROXY ?= https://proxy.golang.org,direct + +# source where the other repos are locally +# has to end with a trailing slash +SRC_DEPS_EXTERNAL_CHECKOUT_DIR ?= ../ + +# names of folder that have to be git-cloned additionally to be able +# to build all code +SRC_DEPS_EXTERNAL_NAMES := images pulp-client +SRC_DEPS_EXTERNAL_DIRS := $(addprefix $(SRC_DEPS_EXTERNAL_CHECKOUT_DIR),$(SRC_DEPS_EXTERNAL_NAMES)) + +$(SRC_DEPS_EXTERNAL_DIRS): + @for DIR in $@; do if ! [ -d $$DIR ]; then echo "Please checkout $$DIR so it is available at $$DIR"; exit 1; fi; done + + +SRC_DEPS_DIRS := internal cmd pkg repositories + +# All files to check for rebuild! +SRC_DEPS := $(shell find $(SRC_DEPS_DIRS) -name *.go -or -name *.json) +SRC_DEPS_EXTERNAL := $(shell find $(SRC_DEPS_EXTERNAL_DIRS) -name *.go) + +# dependencies to rebuild worker +WORKER_SRC_DEPS := $(SRC_DEPS) +# dependencies to rebuild composer +COMPOSER_SRC_DEPS := $(SRC_DEPS) + +GOMODARGS ?= -modfile=go.local.mod +# gcflags "-N -l" for golang to allow debugging +GCFLAGS ?= -gcflags=all=-N -gcflags=all=-l + +CONTAINER_DEPS_COMPOSER := ./containers/osbuild-composer/entrypoint.py +CONTAINER_DEPS_WORKER := ./distribution/osbuild-worker-entrypoint.sh + +USE_BTRFS ?= yes + + +# source where the other repos are locally +# has to end with a trailing slash +SRC_DEPS_EXTERNAL_CHECKOUT_DIR ?= ../ + +COMMON_SRC_DEPS_NAMES := osbuild +COMMON_SRC_DEPS_ORIGIN := $(addprefix $(SRC_DEPS_EXTERNAL_CHECKOUT_DIR),$(COMMON_SRC_DEPS_NAMES)) + +OSBUILD_CONTAINER_INDICATOR := $(SRC_DEPS_EXTERNAL_CHECKOUT_DIR)/osbuild/container_built.info + +MAKE_SUB_CALL := make CONTAINER_EXECUTABLE="$(CONTAINER_EXECUTABLE)" + +$(COMMON_SRC_DEPS_ORIGIN): + @for DIR in $@; do if ! [ -d $$DIR ]; then echo "Please checkout $$DIR so it is available at $$DIR"; exit 1; fi; done + +# we'll trigger the sub-make for osbuild with "osbuild-container" +# and use OSBUILD_CONTAINER_INDICATOR to check if we need to rebuild our containers here +.PHONY: osbuild-container.dev +$(OSBUILD_CONTAINER_INDICATOR) osbuild-container.dev: + $(MAKE_SUB_CALL) -C $(SRC_DEPS_EXTERNAL_CHECKOUT_DIR)osbuild container.dev + +go.local.mod go.local.sum: $(SRC_DEPS_EXTERNAL_DIRS) go.mod $(SRC_DEPS_EXTERNAL) $(WORKER_SRC_DEPS) $(COMPOSER_SRC_DEPS) Makefile + cp go.mod go.local.mod + cp go.sum go.local.sum + + go mod edit $(GOMODARGS) -replace github.com/osbuild/images=$(SRC_DEPS_EXTERNAL_CHECKOUT_DIR)images + go mod edit $(GOMODARGS) -replace github.com/osbuild/pulp-client=$(SRC_DEPS_EXTERNAL_CHECKOUT_DIR)pulp-client + go mod edit $(GOMODARGS) -replace github.com/osbuild/osbuild-composer/pkg/splunk_logger=./pkg/splunk_logger + env GOPROXY=$(GOPROXY) go mod tidy $(GOMODARGS) + env GOPROXY=$(GOPROXY) go mod vendor $(GOMODARGS) + +container_worker_built.info: go.local.mod $(WORKER_SRC_DEPS) $(CONTAINER_WORKER) $(CONTAINER_DEPS_WORKER) $(OSBUILD_CONTAINER_INDICATOR) + $(CONTAINER_EXECUTABLE) build -t $(CONTAINER_IMAGE_WORKER) -f $(CONTAINERFILE_WORKER) --build-arg GOMODARGS="$(GOMODARGS)" --build-arg GCFLAGS="$(GCFLAGS)" --build-arg USE_BTRFS=$(USE_BTRFS) . + echo "Worker last built on" > $@ + date >> $@ + +container_composer_built.info: go.local.mod $(COMPOSER_SRC_DEPS) $(CONTAINERFILE_COMPOSER) $(CONTAINER_DEPS_COMPOSER) $(OSBUILD_CONTAINER_INDICATOR) + $(CONTAINER_EXECUTABLE) build -t $(CONTAINER_IMAGE_COMPOSER) -f $(CONTAINERFILE_COMPOSER) --build-arg GOMODARGS="$(GOMODARGS)" --build-arg GCFLAGS="$(GCFLAGS)" . + echo "Composer last built on" > $@ + date >> $@ + +# build a container with a worker from full source +.PHONY: container_worker.dev +container_worker.dev: osbuild-container.dev container_worker_built.info + +# build a container with the composer from full source +.PHONY: container_composer.dev +container_composer.dev: osbuild-container.dev container_composer_built.info diff --git a/containers/osbuild-composer/entrypoint-onprem.py b/containers/osbuild-composer/entrypoint-onprem.py new file mode 100644 index 0000000000..4404b8f4b4 --- /dev/null +++ b/containers/osbuild-composer/entrypoint-onprem.py @@ -0,0 +1,411 @@ +"""entrypoint - Containerized OSBuild Composer + +This provides the entrypoint for a containerized osbuild-composer image. It +spawns `osbuild-composer` on start and manages it until it exits. The main +purpose of this entrypoint is to prepare everything to be usable from within +a container. +""" + +import argparse +import contextlib +import os +import pathlib +import signal +import socket +import subprocess +import sys +import time + + +class Cli(contextlib.AbstractContextManager): + """Command Line Interface""" + + def __init__(self, argv): + self.args = None + self._argv = argv + self._exitstack = None + self._parser = None + + def _parse_args(self): + self._parser = argparse.ArgumentParser( + add_help=True, + allow_abbrev=False, + argument_default=None, + description="Containerized OSBuild Composer", + prog="container/osbuild-composer", + ) + + self._parser.add_argument( + "--shutdown-wait-period", + type=int, + default=0, + dest="shutdown_wait_period", + help="Wait period in seconds before terminating child processes", + ) + + # --[no-]composer-api + self._parser.add_argument( + "--composer-api", + action="store_true", + dest="composer_api", + help="Enable the composer-API", + ) + self._parser.add_argument( + "--no-composer-api", + action="store_false", + dest="composer_api", + help="Disable the composer-API", + ) + self._parser.add_argument( + "--prometheus", + action="store_true", + dest="prometheus", + help="Enable prometheus listener", + ) + self._parser.add_argument( + "--no-prometheus", + action="store_false", + dest="prometheus", + help="Disable prometheus listener", + ) + self._parser.add_argument( + "--composer-api-port", + type=int, + default=8080, + dest="composer_api_port", + help="Port which the composer-API listens on", + ) + self._parser.add_argument( + "--prometheus-port", + type=int, + default=8008, + dest="prometheus_port", + help="Port which prometheus listens on", + ) + self._parser.add_argument( + "--composer-api-bind-address", + type=str, + default="::", + dest="composer_api_bind_address", + help="Bind the composer API to the specified address", + ) + self._parser.add_argument( + "--prometheus-bind-address", + type=str, + default="::", + dest="prometheus_bind_address", + help="Bind the prometheus listener to the specified address", + ) + + # --[no-]local-worker-api + self._parser.add_argument( + "--local-worker-api", + action="store_true", + dest="local_worker_api", + help="Enable the local-worker-API", + ) + self._parser.add_argument( + "--no-local-worker-api", + action="store_false", + dest="local_worker_api", + help="Disable the local-worker-API", + ) + + # --[no-]remote-worker-api + self._parser.add_argument( + "--remote-worker-api", + action="store_true", + dest="remote_worker_api", + help="Enable the remote-worker-API", + ) + self._parser.add_argument( + "--no-remote-worker-api", + action="store_false", + dest="remote_worker_api", + help="Disable the remote-worker-API", + ) + self._parser.add_argument( + "--remote-worker-api-port", + type=int, + default=8700, + dest="remote_worker_api_port", + help="Port which the remote-worker API listens on", + ) + self._parser.add_argument( + "--remote-worker-api-bind-address", + type=str, + default="::", + dest="remote_worker_api_bind_address", + help="Bind the remote worker API to the specified address", + ) + + # --[no-]weldr-api + self._parser.add_argument( + "--weldr-api", + action="store_true", + dest="weldr_api", + help="Enable the weldr-API", + ) + self._parser.add_argument( + "--no-weldr-api", + action="store_false", + dest="weldr_api", + help="Disable the weldr-API", + ) + + self._parser.set_defaults( + builtin_worker=False, + composer_api=False, + prometheus=False, + local_worker_api=False, + remote_worker_api=False, + weldr_api=False, + ) + + return self._parser.parse_args(self._argv[1:]) + + def __enter__(self): + self._exitstack = contextlib.ExitStack() + self.args = self._parse_args() + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + self._exitstack.close() + self._exitstack = None + + def _prepare_sockets(self): + # Prepare all the API sockets that osbuild-composer expectes, and make + # sure to pass them according to the systemd socket-activation API. + # + # Note that we rely on this being called early, so we get the correct + # FD numbers assigned. We need FD-#3 onwards for compatibility with + # socket activation (because python `subprocess.Popen` does not support + # renumbering the sockets we pass down). + + index = 3 + sockets = [] + names = [] + + # osbuild-composer.socket + if self.args.weldr_api: + print("Create weldr-api socket", file=sys.stderr) + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self._exitstack.enter_context(contextlib.closing(sock)) + sock.bind("/run/weldr/api.socket") + sock.listen() + sockets.append(sock) + + names.append("osbuild-composer.socket") + + assert(sock.fileno() == index) + index += 1 + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self._exitstack.enter_context(contextlib.closing(sock)) + sock.bind("/run/cloudapi/api.socket") + sock.listen() + sockets.append(sock) + + names.append("osbuild-composer.socket") + + assert(sock.fileno() == index) + index += 1 + + # osbuild-composer-api.socket + if self.args.composer_api: + print("Create composer-api socket on port {}".format(self.args.composer_api_port) , file=sys.stderr) + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + self._exitstack.enter_context(contextlib.closing(sock)) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) + sock.bind((self.args.composer_api_bind_address, self.args.composer_api_port)) + sock.listen() + sockets.append(sock) + names.append("osbuild-composer-api.socket") + + assert(sock.fileno() == index) + index += 1 + + # osbuild-composer-prometheus.socket + if self.args.prometheus: + print("Create prometheus socket on port {}".format(self.args.prometheus_port), file=sys.stderr) + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + self._exitstack.enter_context(contextlib.closing(sock)) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) + sock.bind((self.args.prometheus_bind_address, self.args.prometheus_port)) + sock.listen() + sockets.append(sock) + names.append("osbuild-composer-prometheus.socket") + + assert(sock.fileno() == index) + index += 1 + + # osbuild-local-worker.socket + if self.args.local_worker_api: + print("Create local-worker-api socket", file=sys.stderr) + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self._exitstack.enter_context(contextlib.closing(sock)) + sock.bind("/run/osbuild-composer/job.socket") + sock.listen() + sockets.append(sock) + names.append("osbuild-local-worker.socket") + + assert(sock.fileno() == index) + index += 1 + + # osbuild-remote-worker.socket + if self.args.remote_worker_api: + print(f"Create remote-worker-api socket on address [{self.args.remote_worker_api_bind_address}]:{self.args.remote_worker_api_port}", file=sys.stderr) + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + self._exitstack.enter_context(contextlib.closing(sock)) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) + sock.bind((self.args.remote_worker_api_bind_address, self.args.remote_worker_api_port)) + sock.listen(256) + sockets.append(sock) + names.append("osbuild-remote-worker.socket") + + assert(sock.fileno() == index) + index += 1 + + # Prepare FD environment for the child process. + os.environ["LISTEN_FDS"] = str(len(sockets)) + os.environ["LISTEN_FDNAMES"] = ":".join(names) + + return sockets + + @staticmethod + def _spawn_worker(): + cmd = [ + "/usr/libexec/osbuild-composer/osbuild-worker", + "-unix", + "/run/osbuild-composer/job.socket", + ] + + env = os.environ.copy() + env["CACHE_DIRECTORY"] = "/var/cache/osbuild-worker" + env["STATE_DIRECTORY"] = "/var/lib/osbuild-worker" + + return subprocess.Popen( + cmd, + cwd="/", + env=env, + stdin=subprocess.DEVNULL, + stderr=subprocess.STDOUT, + ) + + @staticmethod + def _spawn_composer(sockets): + cmd = [ + "/usr/libexec/osbuild-composer/osbuild-composer", + "-verbose", + ] + + # Prepare the environment for osbuild-composer. Note that we cannot use + # the `env` parameter of `subprocess.Popen()`, because it conflicts + # with the `preexec_fn=` parameter. Therefore, we have to modify the + # caller's environment. + os.environ["CACHE_DIRECTORY"] = "/var/cache/osbuild-composer" + os.environ["STATE_DIRECTORY"] = "/var/lib/osbuild-composer" + + # We need to set `LISTEN_PID=` to the target PID. The only way python + # allows us to do this is to hook into `preexec_fn=`, which is executed + # by `subprocess.Popen()` after forking, but before executing the new + # executable. + preexec_setenv = lambda: os.putenv("LISTEN_PID", str(os.getpid())) + + return subprocess.Popen( + cmd, + cwd="/usr/libexec/osbuild-composer", + stdin=subprocess.DEVNULL, + stderr=subprocess.STDOUT, + pass_fds=[sock.fileno() for sock in sockets], + preexec_fn=preexec_setenv, + ) + + def run(self): + """Program Runtime""" + + proc_composer = None + proc_worker = None + res = 0 + sockets = self._prepare_sockets() + + def handler(signum, frame): + if self.args.shutdown_wait_period: + time.sleep(self.args.shutdown_wait_period) + proc_composer.terminate() + proc_worker.terminate() + + signal.signal(signal.SIGTERM, handler) + + liveness = pathlib.Path('/tmp/osbuild-composer-live') + + liveness.touch() + + try: + should_launch_composer = any([self.args.weldr_api, self.args.composer_api, self.args.local_worker_api, self.args.remote_worker_api]) + if self.args.builtin_worker or not should_launch_composer: + if not should_launch_composer: + print(f"NOTE: launching worker only - no API for composer enabled") + proc_worker = self._spawn_worker() + + if should_launch_composer: + proc_composer = self._spawn_composer(sockets) + + debug_port = os.environ.get('GODEBUG_PORT') + debugger = None + + if debug_port: + # only debug one - either composer or worker if there is no composer + child_pid = proc_composer.pid if proc_composer else proc_worker.pid + debug_target_name = "image-builder-composer" if proc_composer else "image-builder-worker" + + debugger_cmd = [ + "/usr/bin/dlv", + "attach", + "--headless=true", + "--api-version", "2", + "--listen", f":{debug_port}", + str(child_pid), + "/usr/libexec/osbuild-composer/osbuild-composer" + ] + + print(f"NOTE: you HAVE to attach the debugger NOW otherwise { debug_target_name } " + f"will not continue running", file=sys.stderr) + debugger = subprocess.Popen(debugger_cmd) + + if proc_composer: + res = proc_composer.wait() + + if proc_worker: + if proc_composer: + proc_worker.terminate() + proc_worker.wait() + + if debugger: + debugger.wait() + + except KeyboardInterrupt: + if proc_composer: + proc_composer.terminate() + res = proc_composer.wait() + if proc_worker: + proc_worker.terminate() + proc_worker.wait() + except: + if proc_worker: + proc_worker.kill() + if proc_composer: + proc_composer.kill() + raise + finally: + liveness.unlink() + + return res + + +if __name__ == "__main__": + with Cli(sys.argv) as global_main: + sys.exit(global_main.run()) diff --git a/containers/osbuild-composer/entrypoint.py b/containers/osbuild-composer/entrypoint.py index 8fc0b093b7..4404b8f4b4 100644 --- a/containers/osbuild-composer/entrypoint.py +++ b/containers/osbuild-composer/entrypoint.py @@ -194,6 +194,18 @@ def _prepare_sockets(self): sock.bind("/run/weldr/api.socket") sock.listen() sockets.append(sock) + + names.append("osbuild-composer.socket") + + assert(sock.fileno() == index) + index += 1 + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self._exitstack.enter_context(contextlib.closing(sock)) + sock.bind("/run/cloudapi/api.socket") + sock.listen() + sockets.append(sock) + names.append("osbuild-composer.socket") assert(sock.fileno() == index) @@ -333,12 +345,37 @@ def handler(signum, frame): liveness.touch() try: - if self.args.builtin_worker: + should_launch_composer = any([self.args.weldr_api, self.args.composer_api, self.args.local_worker_api, self.args.remote_worker_api]) + if self.args.builtin_worker or not should_launch_composer: + if not should_launch_composer: + print(f"NOTE: launching worker only - no API for composer enabled") proc_worker = self._spawn_worker() - if any([self.args.weldr_api, self.args.composer_api, self.args.local_worker_api, self.args.remote_worker_api]): + if should_launch_composer: proc_composer = self._spawn_composer(sockets) + debug_port = os.environ.get('GODEBUG_PORT') + debugger = None + + if debug_port: + # only debug one - either composer or worker if there is no composer + child_pid = proc_composer.pid if proc_composer else proc_worker.pid + debug_target_name = "image-builder-composer" if proc_composer else "image-builder-worker" + + debugger_cmd = [ + "/usr/bin/dlv", + "attach", + "--headless=true", + "--api-version", "2", + "--listen", f":{debug_port}", + str(child_pid), + "/usr/libexec/osbuild-composer/osbuild-composer" + ] + + print(f"NOTE: you HAVE to attach the debugger NOW otherwise { debug_target_name } " + f"will not continue running", file=sys.stderr) + debugger = subprocess.Popen(debugger_cmd) + if proc_composer: res = proc_composer.wait() @@ -347,6 +384,9 @@ def handler(signum, frame): proc_worker.terminate() proc_worker.wait() + if debugger: + debugger.wait() + except KeyboardInterrupt: if proc_composer: proc_composer.terminate() diff --git a/distribution/Dockerfile-composer b/distribution/Dockerfile-composer new file mode 100644 index 0000000000..819999b41f --- /dev/null +++ b/distribution/Dockerfile-composer @@ -0,0 +1,38 @@ +FROM fedora:39 AS builder +ENV GOBIN=/opt/app-root/src/go/bin + +RUN dnf install -y gpgme-devel libassuan-devel device-mapper-devel golang + +WORKDIR /osbuild-composer +COPY . /osbuild-composer +ENV GOFLAGS="-mod=vendor -tags=exclude_graphdriver_btrfs" + +ARG GOPROXY=https://proxy.golang.org,direct +RUN go env -w GOPROXY=$GOPROXY + +ARG GOMODARGS="" +ARG GCFLAGS="" + +RUN go install $GOMODARGS $GCFLAGS ./cmd/osbuild-composer/ + +FROM registry.access.redhat.com/ubi9/go-toolset:latest AS builder2 +RUN go install github.com/jackc/tern@latest + +FROM fedora:39 + +RUN dnf install -y python3 python3-dnf gpgme libassuan device-mapper-libs delve +RUN mkdir -p "/usr/libexec/osbuild-composer" +RUN mkdir -p "/etc/osbuild-composer/" +RUN mkdir -p "/run/osbuild-composer/" +RUN mkdir -p "/var/cache/osbuild-composer/" +RUN mkdir -p "/var/lib/osbuild-composer/" +RUN mkdir -p "/usr/share/osbuild-composer/" +RUN mkdir -p "/opt/migrate/" +COPY --from=builder /opt/app-root/src/go/bin/osbuild-composer /usr/libexec/osbuild-composer/ +COPY ./containers/osbuild-composer/entrypoint.py /opt/entrypoint.py + +COPY ./pkg/jobqueue/dbjobqueue/schemas /opt/migrate/schemas +COPY --from=builder2 /opt/app-root/src/go/bin/tern /opt/migrate/ + +EXPOSE 8008 8080 8700 +ENTRYPOINT ["python3", "/opt/entrypoint.py", "--remote-worker-api", "--composer-api", "--prometheus", "--shutdown-wait-period", "15"] diff --git a/distribution/Dockerfile-composer.dev b/distribution/Dockerfile-composer.dev new file mode 100644 index 0000000000..74239f5d69 --- /dev/null +++ b/distribution/Dockerfile-composer.dev @@ -0,0 +1,38 @@ +FROM registry.fedoraproject.org/fedora:latest AS builder +ENV GOBIN=/opt/app-root/src/go/bin + +RUN dnf install -y gpgme-devel libassuan-devel device-mapper-devel golang + +WORKDIR /osbuild-composer +COPY . /osbuild-composer +ENV GOFLAGS="-mod=vendor -tags=exclude_graphdriver_btrfs" + +ARG GOPROXY=https://proxy.golang.org,direct +RUN go env -w GOPROXY=$GOPROXY + +ARG GOMODARGS="" +ARG GCFLAGS="" + +RUN go install $GOMODARGS $GCFLAGS ./cmd/osbuild-composer/ + +FROM registry.access.redhat.com/ubi9/go-toolset:latest AS builder2 +RUN go install github.com/jackc/tern@latest + +FROM osbuild_dev + +RUN dnf install -y python3 python3-dnf procps-ng gpgme libassuan device-mapper-libs delve +RUN mkdir -p "/usr/libexec/osbuild-composer" +RUN mkdir -p "/etc/osbuild-composer/" +RUN mkdir -p "/run/osbuild-composer/" +RUN mkdir -p "/var/cache/osbuild-composer/" +RUN mkdir -p "/var/lib/osbuild-composer/" +RUN mkdir -p "/usr/share/osbuild-composer/" +RUN mkdir -p "/opt/migrate/" +COPY --from=builder /opt/app-root/src/go/bin/osbuild-composer /usr/libexec/osbuild-composer/ +COPY ./containers/osbuild-composer/entrypoint.py /opt/entrypoint.py + +COPY ./pkg/jobqueue/dbjobqueue/schemas /opt/migrate/schemas +COPY --from=builder2 /opt/app-root/src/go/bin/tern /opt/migrate/ + +EXPOSE 8008 8080 8700 +ENTRYPOINT ["python3", "/opt/entrypoint.py", "--remote-worker-api", "--composer-api", "--prometheus", "--shutdown-wait-period", "15"] diff --git a/distribution/Dockerfile-fauxauth b/distribution/Dockerfile-fauxauth index 5bb23e4773..52c423f627 100644 --- a/distribution/Dockerfile-fauxauth +++ b/distribution/Dockerfile-fauxauth @@ -4,6 +4,10 @@ FROM registry.access.redhat.com/ubi9/go-toolset:latest AS builder # a repository owned by a different user. COPY --chown=1001 . . ENV GOFLAGS=-mod=vendor + +ARG GOPROXY=https://proxy.golang.org,direct +RUN go env -w GOPROXY=$GOPROXY + RUN go install ./cmd/osbuild-mock-openid-provider/ FROM registry.access.redhat.com/ubi9/ubi-minimal:latest diff --git a/distribution/Dockerfile-fauxauth.dev b/distribution/Dockerfile-fauxauth.dev new file mode 100644 index 0000000000..d01f6e9056 --- /dev/null +++ b/distribution/Dockerfile-fauxauth.dev @@ -0,0 +1,26 @@ +FROM registry.fedoraproject.org/fedora:latest AS builder +ENV GOBIN=/opt/app-root/src/go/bin + +RUN dnf install -y gpgme-devel libassuan-devel device-mapper-devel golang + +WORKDIR /osbuild-composer +COPY . /osbuild-composer +ENV GOFLAGS=-mod=vendor + +ARG GOPROXY=https://proxy.golang.org,direct +RUN go env -w GOPROXY=$GOPROXY + +ARG GOMODARGS="" + +RUN go install $GOMODARGS ./cmd/osbuild-mock-openid-provider/ + +FROM registry.access.redhat.com/ubi9/ubi-minimal:latest +RUN microdnf install -y python3 +RUN mkdir -p "/usr/libexec/osbuild-composer" +RUN mkdir -p "/etc/osbuild-composer/" + +COPY --from=builder /opt/app-root/src/go/bin/osbuild-mock-openid-provider /usr/libexec/osbuild-composer/ +COPY ./containers/fauxauth/fauxauth.py /opt/fauxauth.py + +EXPOSE 8080 8080 +ENTRYPOINT "/opt/fauxauth.py" diff --git a/distribution/Dockerfile-ubi b/distribution/Dockerfile-ubi index d17c2ee562..2fc20dc493 100644 --- a/distribution/Dockerfile-ubi +++ b/distribution/Dockerfile-ubi @@ -13,11 +13,18 @@ ARG COMMIT ENV LDFLAGS="${COMMIT:+-X \'github.com/osbuild/osbuild-composer/internal/common.GitRev=${COMMIT}\'}" ENV LDFLAGS="${LDFLAGS:+-ldflags=\"${LDFLAGS}\"}" ENV GOFLAGS="-mod=vendor -tags=exclude_graphdriver_btrfs" + +ARG GOPROXY=https://proxy.golang.org,direct +RUN go env -w GOPROXY=$GOPROXY + +ARG GOMODARGS="" +ENV GOMODARGS=$GOMODARGS + # if run without "sh -c", podman for some reason executes the command in a way, # which results in the following error: # [1/3] STEP 12/12: RUN go install ${LDFLAGS} ./cmd/osbuild-composer/ # invalid value "\"-X" for flag -ldflags: missing = in = -RUN /usr/bin/sh -c "go install ${LDFLAGS} ./cmd/osbuild-composer/" +RUN /usr/bin/sh -c "go install ${LDFLAGS} ${GOMODARGS} ./cmd/osbuild-composer/" FROM registry.access.redhat.com/ubi9/go-toolset:latest AS builder2 RUN go install github.com/jackc/tern@latest diff --git a/distribution/Dockerfile-worker b/distribution/Dockerfile-worker index b0c2f82b75..097d807827 100644 --- a/distribution/Dockerfile-worker +++ b/distribution/Dockerfile-worker @@ -6,14 +6,22 @@ RUN dnf install -y golang \ krb5-devel \ gpgme-devel \ libassuan-devel + +ARG USE_BTRFS=no +RUN if [[ "$USE_BTRFS" == "yes" ]]; then dnf install -y btrfs-progs-devel device-mapper-devel; fi + WORKDIR /osbuild-composer COPY . /osbuild-composer ENV GOFLAGS=-mod=vendor + +ARG GOPROXY=https://proxy.golang.org,direct +RUN go env -w GOPROXY=$GOPROXY + RUN go install ./cmd/osbuild-worker FROM fedora RUN dnf update -y && dnf upgrade -y -RUN dnf install -y libxcrypt-compat qemu-img osbuild osbuild-ostree +RUN dnf install -y libxcrypt-compat qemu-img osbuild osbuild-ostree osbuild-depsolve-dnf RUN mkdir -p "/usr/libexec/osbuild-composer" RUN mkdir -p "/etc/osbuild-composer/" RUN mkdir -p "/run/osbuild-composer/" diff --git a/distribution/Dockerfile-worker.dev b/distribution/Dockerfile-worker.dev new file mode 100644 index 0000000000..6c53fc594f --- /dev/null +++ b/distribution/Dockerfile-worker.dev @@ -0,0 +1,38 @@ +FROM registry.fedoraproject.org/fedora:latest AS builder +ENV GOBIN=/opt/app-root/src/go/bin +# extra packages are needed +# to compile osbuild +RUN dnf install -y golang \ + krb5-devel \ + gpgme-devel \ + libassuan-devel + +ARG USE_BTRFS=no +RUN if [[ "$USE_BTRFS" == "yes" ]]; then dnf install -y btrfs-progs-devel device-mapper-devel; fi + +WORKDIR /osbuild-composer +COPY . /osbuild-composer +ENV GOFLAGS=-mod=vendor + +ARG GOPROXY=https://proxy.golang.org,direct +RUN go env -w GOPROXY=$GOPROXY + +ARG GOMODARGS="" +ARG GCFLAGS="" + +RUN go install $GOMODARGS $GCFLAGS ./cmd/osbuild-worker + +FROM osbuild_dev + +RUN dnf install -y delve + +RUN mkdir -p "/usr/libexec/osbuild-composer" +RUN mkdir -p "/etc/osbuild-composer/" +RUN mkdir -p "/run/osbuild-composer/" +RUN mkdir -p "/var/cache/osbuild-worker/" +RUN mkdir -p "/var/lib/osbuild-composer/" +RUN mkdir -p "/var/cache/osbuild-composer/output" +COPY --from=builder /opt/app-root/src/go/bin/osbuild-worker /usr/libexec/osbuild-composer/ +COPY distribution/osbuild-worker-entrypoint.sh /usr/libexec/osbuild-composer/ + +ENTRYPOINT ["/usr/libexec/osbuild-composer/osbuild-worker-entrypoint.sh"] diff --git a/distribution/osbuild-worker-entrypoint.sh b/distribution/osbuild-worker-entrypoint.sh new file mode 100755 index 0000000000..b3f1a15fea --- /dev/null +++ b/distribution/osbuild-worker-entrypoint.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +APP="/usr/libexec/osbuild-composer/osbuild-worker" +APP_ARGS="${WORKER_ARGS:-}" + +if [[ -n "${GODEBUG_PORT:-}" ]]; then + echo "With golang debugger enabled on port ${GODEBUG_PORT} ..." + echo "NOTE: you HAVE to attach the debugger NOW otherwise the osbuild-worker will not continue running" + /usr/bin/dlv "--listen=:${GODEBUG_PORT}" --headless=true --api-version=2 exec ${APP} -- "${APP_ARGS}" + exit $? +fi + +${APP} "${APP_ARGS}"