metalos/bzl/service/service.bzl (87 lines of code) (raw):

load("//antlir/bzl:constants.bzl", "REPO_CFG") load("//antlir/bzl:image.bzl", "image") load("//antlir/bzl:shape.bzl", "shape") load("//antlir/bzl:systemd.bzl", "systemd") load("//antlir/bzl/image/feature:defs.bzl", "feature") load("//metalos/os/tests:defs.bzl", "systemd_expectations_test") METALOS_PATH = "metalos" # this is an helper that returns an antlir layer that matches the MetalOS native # service specifications in antlir/docs/metalos/native-services # # - name is the name of the layer # - service_name is the name of the service # - binary is the binary of the service, could either be a buck rule or a file # - parent_layer is the parent layer we want to inherit from, defaults to metalos.layer.base if not provided # - service_binary_path is the path in the layer where the binary should be installed # - user and group are the unix groups # - visibility is a list of path that can use this macro, defaults to //metalos/... and //netos/... def native_service( name, service_name, systemd_service_unit, binary, parent_layer = None, service_binary_path = None, user = "root", group = "root", visibility = None): if not service_binary_path: service_binary_path = "/bin/{}".name if not visibility: visibility = ["//metalos//...", "//netos/..."] if not parent_layer: parent_layer = REPO_CFG.artifact["metalos.layer.base"] image.layer( name = name, parent_layer = parent_layer, flavor = REPO_CFG.antlir_linux_flavor, visibility = visibility, features = [ image.ensure_subdirs_exist( "/", METALOS_PATH, user = user, group = group, mode = 0o0770, ), feature.install( binary, service_binary_path, mode = "a+rx", ), feature.install( systemd_service_unit, "/{}/{}.service".format(METALOS_PATH, service_name), ), ], ) _generate_systemd_expectations_test(name, service_name, systemd_service_unit, visibility) def _generate_systemd_expectations_test(layer_name, service_name, systemd_service_unit, visibility): service_name_t = shape.shape(service_name = str) service_name_instance = shape.new( service_name_t, service_name = service_name, ) # because the service is installed in /metalos/<service_name.service and not in a standard # systemd path we need to create another layer where we install the unit so it will be # visible to systemd and the systemd_expectations_test image.layer( name = "{}-native-service-systemd-expectations".format(layer_name), parent_layer = ":{}".format(layer_name), features = [ systemd.install_unit(systemd_service_unit), # we do not want the unit to start but we still want to analyse it systemd.install_dropin("//metalos/os/tests:skip-unit.conf", systemd_service_unit), systemd.enable_unit(systemd_service_unit, "multi-user.target"), ], ) systemd_expectations_rendered_template = shape.render_template( name = "systemd-expectations-rendered-template", instance = service_name_instance, template = "//metalos/bzl/service:systemd-expectations-template", ) systemd_expectations_test( name = "systemd-expectations", expectations = systemd_expectations_rendered_template, layer = ":{}-native-service-systemd-expectations".format(layer_name), )