diff --git a/Dockerfile b/Dockerfile index 8a1d64b84..321e5455d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -419,6 +419,9 @@ COPY --from=pkg-util-linux-amd64 /lib/libmount.* /rootfs/lib/ COPY --from=pkg-kmod-amd64 /usr/lib/libkmod.* /rootfs/lib/ COPY --from=pkg-kernel-amd64 /lib/modules /rootfs/lib/modules COPY --from=machined-build-amd64 /machined /rootfs/sbin/init +# the orderly_poweroff call by the kernel will call '/sbin/poweroff' +RUN ln /rootfs/sbin/init /rootfs/sbin/poweroff +RUN chmod +x /rootfs/sbin/poweroff # NB: We run the cleanup step before creating extra directories, files, and # symlinks to avoid accidentally cleaning them up. COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh @@ -462,6 +465,9 @@ COPY --from=pkg-util-linux-arm64 /lib/libmount.* /rootfs/lib/ COPY --from=pkg-kmod-arm64 /usr/lib/libkmod.* /rootfs/lib/ COPY --from=pkg-kernel-arm64 /lib/modules /rootfs/lib/modules COPY --from=machined-build-arm64 /machined /rootfs/sbin/init +# the orderly_poweroff call by the kernel will call '/sbin/poweroff' +RUN ln /rootfs/sbin/init /rootfs/sbin/poweroff +RUN chmod +x /rootfs/sbin/poweroff # NB: We run the cleanup step before creating extra directories, files, and # symlinks to avoid accidentally cleaning them up. COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh diff --git a/internal/app/machined/main.go b/internal/app/machined/main.go index e893529e2..45664667e 100644 --- a/internal/app/machined/main.go +++ b/internal/app/machined/main.go @@ -30,6 +30,7 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader" "github.com/talos-systems/talos/internal/app/machined/pkg/system" "github.com/talos-systems/talos/internal/app/machined/pkg/system/services" + "github.com/talos-systems/talos/internal/app/poweroff" "github.com/talos-systems/talos/internal/app/trustd" "github.com/talos-systems/talos/internal/pkg/mount" "github.com/talos-systems/talos/pkg/machinery/api/common" @@ -302,6 +303,11 @@ func main() { case "/trustd": trustd.Main() + return + // Azure uses the hv_utils kernel module to shutdown the node in hyper-v by calling perform_shutdown which will call orderly_poweroff which will call /sbin/poweroff. + case "/sbin/poweroff": + poweroff.Main() + return default: } diff --git a/internal/app/poweroff/main.go b/internal/app/poweroff/main.go new file mode 100644 index 000000000..24ea3ea01 --- /dev/null +++ b/internal/app/poweroff/main.go @@ -0,0 +1,39 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package poweroff + +import ( + "context" + "fmt" + "log" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + + "github.com/talos-systems/talos/pkg/grpc/middleware/authz" + "github.com/talos-systems/talos/pkg/machinery/client" + "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/machinery/role" +) + +// Main is the entrypoint into /sbin/poweroff. +func Main() { + ctx := context.Background() + + md := metadata.Pairs() + authz.SetMetadata(md, role.MakeSet(role.Admin)) + adminCtx := metadata.NewOutgoingContext(ctx, md) + + client, err := client.New(adminCtx, client.WithUnixSocket(constants.APISocketPath), client.WithGRPCDialOptions(grpc.WithTransportCredentials(insecure.NewCredentials()))) + if err != nil { + log.Fatalf(fmt.Errorf("error while creating machinery client: %w", err).Error()) + } + + err = client.Shutdown(adminCtx) + if err != nil { + log.Fatalf(fmt.Errorf("error while sending shutdown command: %w", err).Error()) + } +}