Part 1/?? of packaging/distribution overhaul: generate systemd services with bazel rules adjacent to cmd `go_binary` targets.
--- /dev/null
+exports_files([
+ "systemd.service.in",
+ "systemd-dbus.service.in",
+])
--- /dev/null
+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
--- /dev/null
+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,
+ )
+
+
+
--- /dev/null
+[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
--- /dev/null
+[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
+
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"}"
DBUS_PATH
ORG_NAME
ORG_SLUG
+ EXE_PREFIX
SYSTEM_CONF_DIR
ROOT_CA_NAME
INT_CA_NAME
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
go_library(
name = "apcups_exporter_lib",
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"],
+)
+++ /dev/null
-[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
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
go_library(
name = "http_proxy_lib",
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",
+)
+++ /dev/null
-[Unit]
-Description=Proxy instance %i
-
-[Service]
-Type=notify
-User=http
-ExecStart=/usr/bin/proxy -config=/etc/runtime/proxy/%i.yaml
-
-[Install]
-WantedBy=default.target
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
go_library(
name = "ldap_health_exporter_lib",
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",
+)
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_dbus_service")
go_library(
name = "metricbus_server_lib",
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",
+)
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
go_library(
name = "mtls_exporter_lib",
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",
+ ],
+)
+++ /dev/null
-[Unit]
-Description=Export mTLS certificate status
-Requires=metric-collector.service
-
-[Service]
-Type=notify
-User=root
-ExecStart=/usr/bin/mtls-exporter
-
-[Install]
-WantedBy=default.target
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
go_library(
name = "prometheus_http_discovery_lib",
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",
+)
+++ /dev/null
-[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
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
go_library(
name = "sd_health_exporter_lib",
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",
+)
load("@rules_go//go:def.bzl", "go_binary", "go_library")
+load("//bazel:svc.bzl", "systemd_service")
go_library(
name = "sd_register_lib",
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}",
+)
+++ /dev/null
-[Unit]
-Description=Proxy instance %i
-
-[Service]
-Type=notify
-User=http
-ExecStart=/usr/bin/proxy -config=/etc/runtime/proxy/%i.yaml
-
-[Install]
-WantedBy=default.target
+++ /dev/null
-[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
+++ /dev/null
-[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
+++ /dev/null
-[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
-
+++ /dev/null
-[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
-