]> go.fuhry.dev Git - runtime.git/commitdiff
[cmd/*] use generated systemd services
authorDan Fuhry <dan@fuhry.com>
Sat, 14 Mar 2026 23:30:58 +0000 (19:30 -0400)
committerDan Fuhry <dan@fuhry.com>
Sun, 15 Mar 2026 01:17:53 +0000 (21:17 -0400)
Part 1/?? of packaging/distribution overhaul: generate systemd services with bazel rules adjacent to cmd `go_binary` targets.

23 files changed:
bazel/BUILD.bazel [new file with mode: 0644]
bazel/subst.bzl [new file with mode: 0644]
bazel/svc.bzl [new file with mode: 0644]
bazel/systemd-dbus.service.in [new file with mode: 0644]
bazel/systemd.service.in [new file with mode: 0644]
bazel/workspace-status
cmd/apcups_exporter/BUILD.bazel
cmd/apcups_exporter/systemd/apcupsd-exporter.service [deleted file]
cmd/http_proxy/BUILD.bazel
cmd/http_proxy/systemd/http-proxy@.service [deleted file]
cmd/ldap_health_exporter/BUILD.bazel
cmd/metricbus_server/BUILD.bazel
cmd/mtls_exporter/BUILD.bazel
cmd/mtls_exporter/systemd/mtls-exporter.service [deleted file]
cmd/prometheus_http_discovery/BUILD.bazel
cmd/prometheus_http_discovery/systemd/prometheus-http-discovery.service [deleted file]
cmd/sd_health_exporter/BUILD.bazel
cmd/sd_register/BUILD.bazel
http/proxy/systemd/http-proxy@.service [deleted file]
metrics/metricbus/systemd/metric-collector.service [deleted file]
sd/systemd/sd-health-exporter.service [deleted file]
sd/systemd/sd-register.service [deleted file]
sd/systemd/sd-register@.service [deleted file]

diff --git a/bazel/BUILD.bazel b/bazel/BUILD.bazel
new file mode 100644 (file)
index 0000000..7c43789
--- /dev/null
@@ -0,0 +1,4 @@
+exports_files([
+    "systemd.service.in",
+    "systemd-dbus.service.in",
+])
diff --git a/bazel/subst.bzl b/bazel/subst.bzl
new file mode 100644 (file)
index 0000000..abe5505
--- /dev/null
@@ -0,0 +1,54 @@
+def stamp_subst(
+    name,
+    srcs,
+    outs,
+    additional_vars = {},
+):
+    additional_vars_str = ""
+    for k, v in additional_vars.items():
+        additional_vars_str += '{} {}'.format(k, v)
+
+    native.genrule(
+        name = name,
+        srcs = srcs,
+        outs = outs,
+        cmd_bash = """
+        sedexp=()
+        while read line; do
+            varname="$$(cut -d\\  -f1 <<< "$$line")"
+            len=$$(( $${#varname} + 1 ))
+            varval="$${line:$$len}"
+            sedexp+=("-e" 's;\\$$'"$$varname;$$varval;g")
+        done < <(cat bazel-out/volatile-status.txt; cat <<'EOF'
+"""+additional_vars_str+"""
+EOF
+)
+        sed -r "$${sedexp[@]}" < "$<" > "$@"
+        """,
+        stamp = 1,
+    )
+
+
+def subst(
+    name,  # type: str
+    src,  # type: str
+    out,  # type: str
+    additional_vars = {},  # type: dict[str, str]
+    visibility = [],
+):
+    args = []
+    for k, v in additional_vars.items():
+        args.append("'--var={}={}'".format(k, v.replace("'", "'\\''")))
+
+    native.genrule(
+        name = name,
+        srcs = [src],
+        outs = [out],
+        cmd = """
+        ./$(location //bazel/subst:subst) {} < "$<" > "$@"
+        """.format(' '.join(args)),
+        tools = [
+            "//bazel/subst:subst"
+        ],
+        visibility = visibility,
+    )
\ No newline at end of file
diff --git a/bazel/svc.bzl b/bazel/svc.bzl
new file mode 100644 (file)
index 0000000..4ee239c
--- /dev/null
@@ -0,0 +1,81 @@
+load("//bazel:subst.bzl", "subst")
+
+def systemd_service(
+    name,
+    exe,
+    args = [],
+    description = "runtime service with no description provided",
+    deps = ["network-online.target"],
+    user = "nobody",
+    group = "nobody",
+    type = "simple",
+    environment_file = None,
+    visibility = ["//visibility:public"],
+):
+    installed_exe_name = exe.replace("_", "-")
+    environment_file = environment_file or (
+        '${const:ExePrefix}'+installed_exe_name+'@%i'
+        if '@' in name
+        else '${const:ExePrefix}'+installed_exe_name
+    )
+    exvars = {
+        "WANTS": " ".join(deps).replace('$', '$$'),
+        "AFTER": " ".join(deps).replace('$', '$$'),
+        "DESCRIPTION": description.replace('$', '$$'),
+        "EXE": installed_exe_name,
+        "ENV_FILE": environment_file.replace('$', '$$'),
+        "USER": user,
+        "GROUP": group,
+        "ARGS": " ".join(args).replace('$', '$$'),
+        "TYPE": type,
+    }
+
+    subst(
+        name = name.replace("-", "_") + "_systemd_service",
+        src = "//bazel:systemd.service.in",
+        out = name + ".service",
+        additional_vars = exvars,
+        visibility = visibility,
+    )
+
+
+def systemd_dbus_service(
+    name,
+    exe,
+    bus_name,
+    args = [],
+    description = "runtime service with no description provided",
+    deps = ["network-online.target"],
+    user = "nobody",
+    group = "nobody",
+    type = "simple",
+    environment_file = None,
+    visibility = ["//visibility:public"],
+):
+    installed_exe_name = exe.replace("_", "-")
+    environment_file = environment_file or (
+        '{}@%i'.format(installed_exe_name) if '@' in name else installed_exe_name
+    )
+    exvars = {
+        "WANTS": " ".join(deps).replace('$', '$$'),
+        "AFTER": " ".join(deps).replace('$', '$$'),
+        "DESCRIPTION": description.replace('$', '$$'),
+        "EXE": installed_exe_name,
+        "ENV_FILE": environment_file.replace('$', '$$'),
+        "BUS_NAME": bus_name,
+        "USER": user,
+        "GROUP": group,
+        "ARGS": " ".join(args).replace('$', '$$'),
+        "TYPE": type,
+    }
+
+    subst(
+        name = name.replace("-", "_") + "_systemd_service",
+        src = "//bazel:systemd-dbus.service.in",
+        out = name + ".service",
+        additional_vars = exvars,
+        visibility = visibility,
+    )
+
+
+    
diff --git a/bazel/systemd-dbus.service.in b/bazel/systemd-dbus.service.in
new file mode 100644 (file)
index 0000000..18947f7
--- /dev/null
@@ -0,0 +1,15 @@
+[Unit]
+Description=${DESCRIPTION}
+Wants=${WANTS:-network-online.target}
+After=${AFTER:-network-online.target}
+
+[Service]
+Type=dbus
+BusName=${const:DbusPrefix}.${BUS_NAME}.v1
+User=${USER:-nobody}
+Group=${GROUP:-${USER:-nobody}}
+ExecStart=${EXEDIR:-/usr/bin}/${const:EXE_PREFIX}${EXE} ${ARGS:-}
+
+[Install]
+Alias=${const:DbusPrefix}.${BUS_NAME}.service
+WantedBy=multi-user.target
diff --git a/bazel/systemd.service.in b/bazel/systemd.service.in
new file mode 100644 (file)
index 0000000..bcfabff
--- /dev/null
@@ -0,0 +1,15 @@
+[Unit]
+Description=${DESCRIPTION}
+Wants=${WANTS:-network-online.target}
+After=${AFTER:-network-online.target}
+
+[Service]
+Type=${TYPE}
+User=${USER:-nobody}
+Group=${GROUP:-${USER:-nobody}}
+EnvironmentFile=-/etc/conf.d/${ENV_FILE:-${const:ExePrefix}${EXE}}
+ExecStart=${EXEDIR:-/usr/bin}/${const:ExePrefix}${EXE} ${ARGS:-}
+
+[Install]
+WantedBy=multi-user.target
+
index 911a78ea9b76e0ac675388ee95709f5544fe1741..44a1f997bc177c1af1351588f99c4d1be4698a77 100755 (executable)
@@ -17,6 +17,7 @@ DBUS_PREFIX="${DBUS_PREFIX:-"dev.fuhry.runtime"}"
 DBUS_PATH="${DBUS_PATH:-"/${DBUS_PREFIX//\./\/}"}"
 ORG_NAME="${ORG_NAME:-"FooCorp"}"
 ORG_SLUG="${ORG_SLUG:-"runtime"}"
+EXE_PREFIX="${EXE_PREFIX:-}"
 SYSTEM_CONF_DIR="${SYSTEM_CONF_DIR:-"/etc/${ORG_SLUG}"}"
 ROOT_CA_NAME="${ROOT_CA_NAME:-"${ORG_NAME} Root"}"
 INT_CA_NAME="${INT_CA_NAME:-"${ORG_NAME} Intermediate mTLS"}"
@@ -38,6 +39,7 @@ vars=(
        DBUS_PATH
        ORG_NAME
        ORG_SLUG
+       EXE_PREFIX
        SYSTEM_CONF_DIR
        ROOT_CA_NAME
        INT_CA_NAME
index 535738011d34c4287b6cfff76331eb697be9f4bd..6d7512fe613e660ea20304b5537d495657ea8cd6 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
 
 go_library(
     name = "apcups_exporter_lib",
@@ -19,3 +20,28 @@ go_binary(
     embed = [":apcups_exporter_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_service(
+    name = "apcupsd-exporter",
+    description = "apcupsd-exporter polls APC uninterruptible power supplies (UPSes) via apcupsd and exports metrics via metric-collector",
+    exe = "apcups_exporter",
+    group = "daemon",
+    type = "notify",
+    user = "daemon",
+    deps = ["apcupsd.service"],
+)
+
+systemd_service(
+    name = "apcupsd-exporter@",
+    args = [
+        "--metricbus.client.service-discriminator=%i",
+        "$APCUPSD_EXPORTER_ARGS",
+    ],
+    description = "apcupsd-exporter polls apcupsd for UPS %i and exports metrics via metric-collector",
+    environment_file = "$${const:ExePrefix}apcupsd-exporter@%i",
+    exe = "apcups_exporter",
+    group = "daemon",
+    type = "notify",
+    user = "daemon",
+    deps = ["apcupsd.service"],
+)
diff --git a/cmd/apcups_exporter/systemd/apcupsd-exporter.service b/cmd/apcups_exporter/systemd/apcupsd-exporter.service
deleted file mode 100644 (file)
index b815ead..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-Description=Export stats from apcupsd via metric-collector
-Requires=apcupsd.service
-
-[Service]
-Type=notify
-User=daemon
-ExecStart=/usr/bin/apcupsd-exporter
-
-[Install]
-WantedBy=default.target
index edf922b43c8983a7e05d5a4fc6d92562570d96a9..e70103054d9d02ba7004b728dc52bf7a4c8fe84e 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
 
 go_library(
     name = "http_proxy_lib",
@@ -21,3 +22,15 @@ go_binary(
     embed = [":http_proxy_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_service(
+    name = "http-proxy@",
+    args = [
+        "--config=${const:SystemConfDir}/proxy/%i.yaml",
+    ],
+    description = "http-proxy instance %i",
+    exe = "http_proxy",
+    group = "http",
+    type = "notify",
+    user = "http",
+)
diff --git a/cmd/http_proxy/systemd/http-proxy@.service b/cmd/http_proxy/systemd/http-proxy@.service
deleted file mode 100644 (file)
index 9175d0b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=Proxy instance %i
-
-[Service]
-Type=notify
-User=http
-ExecStart=/usr/bin/proxy -config=/etc/runtime/proxy/%i.yaml
-
-[Install]
-WantedBy=default.target
index ed82caaa678124ca310dbf50d46ec88f44b97fc0..472fe0075618f55135c0059154824c6839a8b95e 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
 
 go_library(
     name = "ldap_health_exporter_lib",
@@ -20,3 +21,16 @@ go_binary(
     embed = [":ldap_health_exporter_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_service(
+    name = "ldap-health-exporter@",
+    args = [
+        "--webCfgFile=/etc/prometheus-node-exporter/web-config.yml",
+        "--ldapAddr=%i:636",
+        "--mtlsId=slapmon",
+        "--interval=30s",
+    ],
+    description = "Monitor LDAP server health on %i",
+    exe = "ldap_health_exporter",
+    user = "slapmon",
+)
index 46abb28f5472c2d3bc62c6f974df1f5d1939105d..dceea288947fe6cac68f42416af55d020bfd671b 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_dbus_service")
 
 go_library(
     name = "metricbus_server_lib",
@@ -17,3 +18,15 @@ go_binary(
     embed = [":metricbus_server_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_dbus_service(
+    name = "metric-collector",
+    args = [
+        "--mtls.id=node-exporter",
+    ],
+    bus_name = "metrics.MetricCollector",
+    description = "metricbus-server collects metrics from other services via dbus and exports them via a single OpenTelemetry endpoint",
+    exe = "metricbus_server",
+    group = "node_exporter",
+    user = "node_exporter",
+)
index 24d297886fefd2ac94532cdaee1395f240ff07a6..1e59ec1052385d21d90c5c9fe47707bf267fc033 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
 
 go_library(
     name = "mtls_exporter_lib",
@@ -17,3 +18,15 @@ go_binary(
     embed = [":mtls_exporter_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_service(
+    name = "mtls-exporter",
+    description = "mtls-exporter exports metrics for health and remaining lifetime of mTLS certificates",
+    exe = "mtls_exporter",
+    group = "root",
+    type = "notify",
+    user = "root",
+    deps = [
+        "${const:ExePrefix}metric-collector.service",
+    ],
+)
diff --git a/cmd/mtls_exporter/systemd/mtls-exporter.service b/cmd/mtls_exporter/systemd/mtls-exporter.service
deleted file mode 100644 (file)
index f6939ac..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-Description=Export mTLS certificate status
-Requires=metric-collector.service
-
-[Service]
-Type=notify
-User=root
-ExecStart=/usr/bin/mtls-exporter
-
-[Install]
-WantedBy=default.target
index a35c126934938b0683ba9f51c0a977a56de4cdbc..b98bc6db85d5dfadfa38bcf619c4089631fb5819 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
 
 go_library(
     name = "prometheus_http_discovery_lib",
@@ -20,3 +21,10 @@ go_binary(
     embed = [":prometheus_http_discovery_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_service(
+    name = "prometheus-http-discovery",
+    description = "Prometheus HTTP endpoint discoverer monitors service discovery entries and returns Prometheus http_sd_config JSON",
+    exe = "prometheus_http_discovery",
+    type = "notify",
+)
diff --git a/cmd/prometheus_http_discovery/systemd/prometheus-http-discovery.service b/cmd/prometheus_http_discovery/systemd/prometheus-http-discovery.service
deleted file mode 100644 (file)
index 9b63216..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=Prometheus HTTP endpoint discoverer monitors service discovery entries and returns Prometheus http_sd_config JSON
-
-[Service]
-Type=notify
-User=nobody
-ExecStart=/usr/bin/prometheus-http-discovery
-
-[Install]
-WantedBy=default.target
index 7030a73a6e7179d9b8833dc4e1f11f0340eab832..da61a045491962433d3ec15754191a36874f0bf6 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
 
 go_library(
     name = "sd_health_exporter_lib",
@@ -18,3 +19,14 @@ go_binary(
     embed = [":sd_health_exporter_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_service(
+    name = "sd-health-exporter",
+    args = [
+        "--mtls.id=node-exporter",
+    ],
+    description = "sd-health-exporter exports Prometheus metrics for service health",
+    exe = "sd_health_exporter",
+    group = "node_exporter",
+    user = "node_exporter",
+)
index 63e4a58533384cfc15261729d270a7b75a2b9432..1ac2f6b4d3d2142ce4b949565ec500ff6363c9bf 100644 (file)
@@ -1,4 +1,5 @@
 load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
 
 go_library(
     name = "sd_register_lib",
@@ -19,3 +20,27 @@ go_binary(
     embed = [":sd_register_lib"],
     visibility = ["//visibility:public"],
 )
+
+systemd_service(
+    name = "sd-register",
+    args = [
+        "--service=${const:SystemConfDir}/sd",
+    ],
+    description = "sd-register registers services in service discovery and continually renews them based on health-checks",
+    exe = "sd-register",
+    group = "$${const:OrgSlug}",
+    user = "$${const:OrgSlug}",
+)
+
+systemd_service(
+    name = "sd-register@",
+    args = [
+        "--mtls.id=etcd-client",
+        "--service=${const:SystemConfDir}/sd/%i",
+        "--domain=%i",
+    ],
+    description = "sd-register registers services for the domain %i in service discovery and continually renews them based on health-checks",
+    exe = "sd-register",
+    group = "$${const:OrgSlug}",
+    user = "$${const:OrgSlug}",
+)
diff --git a/http/proxy/systemd/http-proxy@.service b/http/proxy/systemd/http-proxy@.service
deleted file mode 100644 (file)
index 9175d0b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=Proxy instance %i
-
-[Service]
-Type=notify
-User=http
-ExecStart=/usr/bin/proxy -config=/etc/runtime/proxy/%i.yaml
-
-[Install]
-WantedBy=default.target
diff --git a/metrics/metricbus/systemd/metric-collector.service b/metrics/metricbus/systemd/metric-collector.service
deleted file mode 100644 (file)
index caff109..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-[Unit]
-Description=Metric Collector
-
-[Service]
-Type=dbus
-User=node_exporter
-BusName=dev.fuhry.runtime.metrics.MetricCollector.v1
-ExecStart=/usr/bin/metricbus-collector -mtls.id=node-exporter
-
-[Install]
-Alias=dev.fuhry.runtime.metrics.MetricCollector.service
-WantedBy=default.target
diff --git a/sd/systemd/sd-health-exporter.service b/sd/systemd/sd-health-exporter.service
deleted file mode 100644 (file)
index 408b0b7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit]
-Description=Export Prometheus metrics for service health
-Wants=systemd-networkd-wait-online.service
-After=systemd-networkd-wait-online.service
-
-[Service]
-Type=simple
-User=node_exporter
-Group=node_exporter
-Environment=MTLS_IDENTITY=node-exporter
-ExecStart=/usr/bin/health-exporter -mtls.id=${MTLS_IDENTITY}
-
-[Install]
-WantedBy=multi-user.target
diff --git a/sd/systemd/sd-register.service b/sd/systemd/sd-register.service
deleted file mode 100644 (file)
index afb56dc..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit]
-Description=Service discovery and health checking for %i
-Wants=network-online.target
-After=network-online.target
-
-[Service]
-Type=simple
-User=nobody
-Group=nobody
-ExecStart=/usr/bin/sd-register -service /etc/runtime/sd
-
-[Install]
-WantedBy=multi-user.target
-
diff --git a/sd/systemd/sd-register@.service b/sd/systemd/sd-register@.service
deleted file mode 100644 (file)
index fa87160..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit]
-Description=Service discovery and health checking for %i
-Wants=network-online.target
-After=network-online.target
-
-[Service]
-Type=simple
-User=nobody
-Group=nobody
-ExecStart=/usr/bin/sd-register -mtls.id=etcd-client -service /etc/runtime/sd/%i -domain %i
-
-[Install]
-WantedBy=multi-user.target
-