From 7376b593906723f6f50bddfde55820dff5e3e542 Mon Sep 17 00:00:00 2001 From: Omer Preminger Date: Thu, 2 Nov 2023 13:31:26 -0400 Subject: [PATCH] reorganize files/pkgs --- cmd/internal/cli/build_linux.go | 34 ++++-- .../pkg/build/buildkit/client/client.go | 111 ++++++++++-------- .../pkg/build/buildkit/daemon/authprovider.go | 4 +- .../pkg/build/buildkit/daemon/daemon.go | 8 +- .../pkg/build/buildkit/daemon/executor.go | 12 +- 5 files changed, 94 insertions(+), 75 deletions(-) rename cmd/internal/cli/build_dockerfile_linux.go => internal/pkg/build/buildkit/client/client.go (82%) rename cmd/internal/cli/build_bkauth_linux.go => internal/pkg/build/buildkit/daemon/authprovider.go (98%) rename cmd/internal/cli/build_buildkitd_linux.go => internal/pkg/build/buildkit/daemon/daemon.go (98%) rename cmd/internal/cli/build_bkexec_linux.go => internal/pkg/build/buildkit/daemon/executor.go (97%) diff --git a/cmd/internal/cli/build_linux.go b/cmd/internal/cli/build_linux.go index 2dae692dff..a074e37278 100644 --- a/cmd/internal/cli/build_linux.go +++ b/cmd/internal/cli/build_linux.go @@ -18,10 +18,12 @@ import ( "strings" "syscall" + ocitypes "github.com/containers/image/v5/types" "github.com/spf13/cobra" keyclient "github.com/sylabs/scs-key-client/client" "github.com/sylabs/singularity/v4/internal/pkg/build" "github.com/sylabs/singularity/v4/internal/pkg/build/args" + bkclient "github.com/sylabs/singularity/v4/internal/pkg/build/buildkit/client" "github.com/sylabs/singularity/v4/internal/pkg/build/remotebuilder" "github.com/sylabs/singularity/v4/internal/pkg/buildcfg" "github.com/sylabs/singularity/v4/internal/pkg/cache" @@ -197,13 +199,26 @@ func runBuild(cmd *cobra.Command, args []string) { sylog.Fatalf("While checking build target: %s", err) } - switch { - case buildArgs.remote: + if buildArgs.remote { runBuildRemote(cmd.Context(), cmd, dest, spec) - case isOCI: - runBuildOCI(cmd.Context(), cmd, dest, spec) - default: - runBuildLocal(cmd.Context(), cmd, dest, spec) + return + } + + authConf, err := makeDockerCredentials(cmd) + if err != nil { + sylog.Fatalf("While creating Docker credentials: %v", err) + } + + if isOCI { + bkOpts := &bkclient.Opts{ + AuthConf: authConf, + ReqAuthFile: reqAuthFile, + BuildVarArgs: buildArgs.buildVarArgs, + BuildVarArgFile: buildArgs.buildVarArgFile, + } + bkclient.Run(cmd.Context(), bkOpts, dest, spec) + } else { + runBuildLocal(cmd.Context(), authConf, cmd, dest, spec) } sylog.Infof("Build complete: %s", dest) @@ -333,7 +348,7 @@ func runBuildRemote(ctx context.Context, cmd *cobra.Command, dst, spec string) { } } -func runBuildLocal(ctx context.Context, cmd *cobra.Command, dst, spec string) { +func runBuildLocal(ctx context.Context, authConf *ocitypes.DockerAuthConfig, cmd *cobra.Command, dst, spec string) { var keyInfo *cryptkey.KeyInfo if buildArgs.encrypt || promptForPassphrase || cmd.Flags().Lookup("pem-path").Changed { if os.Getuid() != 0 { @@ -363,11 +378,6 @@ func runBuildLocal(ctx context.Context, cmd *cobra.Command, dst, spec string) { sylog.Fatalf("Could not check build sections: %v", err) } - authConf, err := makeDockerCredentials(cmd) - if err != nil { - sylog.Fatalf("While creating Docker credentials: %v", err) - } - // parse definition to determine build source buildArgsMap, err := args.ReadBuildArgs(buildArgs.buildVarArgs, buildArgs.buildVarArgFile) if err != nil { diff --git a/cmd/internal/cli/build_dockerfile_linux.go b/internal/pkg/build/buildkit/client/client.go similarity index 82% rename from cmd/internal/cli/build_dockerfile_linux.go rename to internal/pkg/build/buildkit/client/client.go index ca9718936a..7a844bfe70 100644 --- a/cmd/internal/cli/build_dockerfile_linux.go +++ b/internal/pkg/build/buildkit/client/client.go @@ -19,7 +19,7 @@ // This file contains modified code originally taken from: // github.com/moby/buildkit/blob/v0.12.3/examples/build-using-dockerfile/main.go -package cli +package client import ( "bufio" @@ -37,8 +37,8 @@ import ( "github.com/moby/buildkit/session" "github.com/moby/buildkit/util/progress/progressui" "github.com/pkg/errors" - "github.com/spf13/cobra" "github.com/sylabs/singularity/v4/internal/pkg/build/args" + bkdaemon "github.com/sylabs/singularity/v4/internal/pkg/build/buildkit/daemon" "github.com/sylabs/singularity/v4/internal/pkg/client/ocisif" "github.com/sylabs/singularity/v4/internal/pkg/remote/credential/ociauth" "github.com/sylabs/singularity/v4/pkg/sylog" @@ -51,7 +51,59 @@ const ( bkLaunchTimeout = 30 * time.Second ) -func buildImage(ctx context.Context, authConf *ocitypes.DockerAuthConfig, tarFile *os.File, listenSocket, spec string, clientsideFrontend bool) error { +type Opts struct { + // Optional Docker authentication config derived from interactive login or + // environment variables + AuthConf *ocitypes.DockerAuthConfig + // Optional user requested authentication file for writing/reading OCI + // registry credentials + ReqAuthFile string + // Variables passed to build procedure. + BuildVarArgs []string + // Variables file passed to build procedure. + BuildVarArgFile string +} + +func Run(ctx context.Context, opts *Opts, dest, spec string) { + listenSocket := ensureBuildkitd(ctx) + if listenSocket == "" { + sylog.Fatalf("Failed to launch buildkitd daemon within specified timeout (%v).", bkLaunchTimeout) + } + + tarFile, err := os.CreateTemp("", "singularity-buildkit-tar-") + if err != nil { + sylog.Fatalf("While trying to build tar image from dockerfile: %v", err) + } + defer tarFile.Close() + defer os.Remove(tarFile.Name()) + + if err := buildImage(ctx, opts, tarFile, listenSocket, spec, false); err != nil { + sylog.Fatalf("While building from dockerfile: %v", err) + } + sylog.Debugf("Saved OCI image as tar: %s", tarFile.Name()) + tarFile.Close() + + if _, err := ocisif.PullOCISIF(ctx, nil, dest, "oci-archive:"+tarFile.Name(), ocisif.PullOptions{}); err != nil { + sylog.Fatalf("While converting OCI tar image to OCI-SIF: %v", err) + } +} + +// isBuildkitdRunning tries to determine whether there's already an instance of buildkitd running. +func isBuildkitdRunning(ctx context.Context) bool { + c, err := client.New(ctx, bkDefaultSocket, client.WithFailFast()) + if err != nil { + return false + } + defer c.Close() + + cc := c.ControlClient() + ir := moby_buildkit_v1.InfoRequest{} + _, err = cc.Info(ctx, &ir) + + return (err == nil) +} + +func buildImage(ctx context.Context, opts *Opts, tarFile *os.File, listenSocket, spec string, clientsideFrontend bool) error { c, err := client.New(ctx, listenSocket, client.WithFailFast()) if err != nil { return err @@ -64,7 +116,7 @@ func buildImage(ctx context.Context, authConf *ocitypes.DockerAuthConfig, tarFil defer os.RemoveAll(buildDir) pipeR, pipeW := io.Pipe() - solveOpt, err := newSolveOpt(ctx, authConf, pipeW, buildDir, spec, clientsideFrontend) + solveOpt, err := newSolveOpt(ctx, opts, pipeW, buildDir, spec, clientsideFrontend) if err != nil { return err } @@ -106,7 +158,7 @@ func buildImage(ctx context.Context, authConf *ocitypes.DockerAuthConfig, tarFil return eg.Wait() } -func newSolveOpt(_ context.Context, authConf *ocitypes.DockerAuthConfig, w io.WriteCloser, buildDir, spec string, clientsideFrontend bool) (*client.SolveOpt, error) { +func newSolveOpt(_ context.Context, opts *Opts, w io.WriteCloser, buildDir, spec string, clientsideFrontend bool) (*client.SolveOpt, error) { if buildDir == "" { return nil, errors.New("please specify build context (e.g. \".\" for the current directory)") } else if buildDir == "-" { @@ -131,9 +183,9 @@ func newSolveOpt(_ context.Context, authConf *ocitypes.DockerAuthConfig, w io.Wr frontendAttrs["no-cache"] = "" - attachable := []session.Attachable{NewDockerAuthProvider(authConf, ociauth.ChooseAuthFile(reqAuthFile))} + attachable := []session.Attachable{bkdaemon.NewAuthProvider(opts.AuthConf, ociauth.ChooseAuthFile(opts.ReqAuthFile))} - buildArgsMap, err := args.ReadBuildArgs(buildArgs.buildVarArgs, buildArgs.buildVarArgFile) + buildArgsMap, err := args.ReadBuildArgs(opts.BuildVarArgs, opts.BuildVarArgFile) if err != nil { return nil, err } @@ -171,34 +223,6 @@ func writeDockerTar(r io.Reader, outputFile *os.File) error { return nil } -func runBuildOCI(ctx context.Context, cmd *cobra.Command, dest, spec string) { - authConf, err := makeDockerCredentials(cmd) - if err != nil { - sylog.Fatalf("While trying to process docker login credentials: %v", err) - } - listenSocket := ensureBuildkitd(ctx) - if listenSocket == "" { - sylog.Fatalf("Failed to launch buildkitd daemon within specified timeout (%v).", bkLaunchTimeout) - } - - tarFile, err := os.CreateTemp("", "singularity-buildkit-tar-") - if err != nil { - sylog.Fatalf("While trying to build tar image from dockerfile: %v", err) - } - defer tarFile.Close() - defer os.Remove(tarFile.Name()) - - if err := buildImage(ctx, authConf, tarFile, listenSocket, spec, false); err != nil { - sylog.Fatalf("While building from dockerfile: %v", err) - } - sylog.Debugf("Saved OCI image as tar: %s", tarFile.Name()) - tarFile.Close() - - if _, err := ocisif.PullOCISIF(ctx, nil, dest, "oci-archive:"+tarFile.Name(), ocisif.PullOptions{}); err != nil { - sylog.Fatalf("While converting OCI tar image to OCI-SIF: %v", err) - } -} - // ensureBuildkitd checks if a buildkitd daemon is already running, and if not, // launches one. Once the server is ready, the value true will be sent over the // provided readyChan. Make sure this is a buffered channel with sufficient room @@ -212,7 +236,7 @@ func ensureBuildkitd(ctx context.Context) string { sylog.Infof("Did not find usable running buildkitd daemon; spawning our own.") socketChan := make(chan string, 1) go func() { - if err := runBuildkitd(ctx, socketChan); err != nil { + if err := bkdaemon.Run(ctx, socketChan); err != nil { sylog.Fatalf("buildkitd returned error: %v", err) } }() @@ -223,18 +247,3 @@ func ensureBuildkitd(ctx context.Context) string { return <-socketChan } - -// isBuildkitdRunning tries to determine whether there's already an instance of buildkitd running. -func isBuildkitdRunning(ctx context.Context) bool { - c, err := client.New(ctx, bkDefaultSocket, client.WithFailFast()) - if err != nil { - return false - } - defer c.Close() - - cc := c.ControlClient() - ir := moby_buildkit_v1.InfoRequest{} - _, err = cc.Info(ctx, &ir) - - return (err == nil) -} diff --git a/cmd/internal/cli/build_bkauth_linux.go b/internal/pkg/build/buildkit/daemon/authprovider.go similarity index 98% rename from cmd/internal/cli/build_bkauth_linux.go rename to internal/pkg/build/buildkit/daemon/authprovider.go index bd55b9999a..9b7d514267 100644 --- a/cmd/internal/cli/build_bkauth_linux.go +++ b/internal/pkg/build/buildkit/daemon/authprovider.go @@ -19,7 +19,7 @@ // This file contains modified code originally taken from: // github.com/moby/buildkit/tree/v0.12.3/session/auth/authprovider -package cli +package daemon import ( "context" @@ -65,7 +65,7 @@ const ( dockerHubRegistryHost = "registry-1.docker.io" ) -func NewDockerAuthProvider(authConf *ocitypes.DockerAuthConfig, reqAuthFile string) session.Attachable { +func NewAuthProvider(authConf *ocitypes.DockerAuthConfig, reqAuthFile string) session.Attachable { if authConf != nil { return &authProvider{ authConfigCache: map[string]*types.AuthConfig{}, diff --git a/cmd/internal/cli/build_buildkitd_linux.go b/internal/pkg/build/buildkit/daemon/daemon.go similarity index 98% rename from cmd/internal/cli/build_buildkitd_linux.go rename to internal/pkg/build/buildkit/daemon/daemon.go index 8b301e5077..0eca0b2b9b 100644 --- a/cmd/internal/cli/build_buildkitd_linux.go +++ b/internal/pkg/build/buildkit/daemon/daemon.go @@ -19,7 +19,7 @@ // This file contains modified code originally taken from: // github.com/moby/buildkit/tree/v0.12.3/cmd/buildkitd -package cli +package daemon import ( "context" @@ -122,10 +122,10 @@ func init() { ) } -// runBuildkitd runs a new buildkitd daemon. Once the server is ready, the path +// Run runs a new buildkitd daemon. Once the server is ready, the path // of the unix socket will be sent over the provided channel. Make sure this is // a buffered channel with sufficient room to avoid deadlocks. -func runBuildkitd(ctx context.Context, socketChan chan<- string) error { +func Run(ctx context.Context, socketChan chan<- string) error { cfg, err := config.LoadFile(defaultConfigPath()) if err != nil { return err @@ -262,7 +262,7 @@ func ociWorkerInitializer(ctx context.Context, common workerInitializerOpt) ([]w sylog.Infof("Using runc runtime for buildkitd daemon.") } - opt, err := NewBkWorkerOpt(ctx, common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary, cfg.ApparmorProfile, cfg.SELinux, parallelismSem, "", cfg.DefaultCgroupParent) + opt, err := NewWorkerOpt(ctx, common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary, cfg.ApparmorProfile, cfg.SELinux, parallelismSem, "", cfg.DefaultCgroupParent) if err != nil { return nil, err } diff --git a/cmd/internal/cli/build_bkexec_linux.go b/internal/pkg/build/buildkit/daemon/executor.go similarity index 97% rename from cmd/internal/cli/build_bkexec_linux.go rename to internal/pkg/build/buildkit/daemon/executor.go index e9c273e81a..7b1726b0e6 100644 --- a/cmd/internal/cli/build_bkexec_linux.go +++ b/internal/pkg/build/buildkit/daemon/executor.go @@ -20,7 +20,7 @@ // github.com/moby/buildkit/tree/v0.12.3/executor // github.com/moby/buildkit/tree/v0.12.3/worker/runc -package cli +package daemon import ( "context" @@ -79,8 +79,8 @@ type BkSnapshotterFactory struct { New func(root string) (ctdsnapshot.Snapshotter, error) } -// NewBkWorkerOpt creates a WorkerOpt. -func NewBkWorkerOpt(ctx context.Context, root string, snFactory BkSnapshotterFactory, rootless bool, processMode bkoci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, nopt netproviders.Opt, dns *bkoci.DNSConfig, binary, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket, defaultCgroupParent string) (base.WorkerOpt, error) { +// NewWorkerOpt creates a WorkerOpt. +func NewWorkerOpt(ctx context.Context, root string, snFactory BkSnapshotterFactory, rootless bool, processMode bkoci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, nopt netproviders.Opt, dns *bkoci.DNSConfig, binary, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket, defaultCgroupParent string) (base.WorkerOpt, error) { var opt base.WorkerOpt name := "runc-" + snFactory.Name root = filepath.Join(root, name) @@ -106,7 +106,7 @@ func NewBkWorkerOpt(ctx context.Context, root string, snFactory BkSnapshotterFac return opt, err } - exe, err := NewBkBuildExecutor(BkWorkerOpt{ + exe, err := NewBuildExecutor(WorkerOpt{ // Root directory Root: filepath.Join(root, "executor"), // If user has specified OCI worker binary, it will be sent to the runc executor to find and use @@ -214,7 +214,7 @@ func NewBkWorkerOpt(ctx context.Context, root string, snFactory BkSnapshotterFac return opt, nil } -type BkWorkerOpt struct { +type WorkerOpt struct { // root directory Root string CommandCandidates []string @@ -259,7 +259,7 @@ type buildExecutor struct { isRunc bool } -func NewBkBuildExecutor(opt BkWorkerOpt, networkProviders map[pb.NetMode]bknet.Provider) (executor.Executor, error) { +func NewBuildExecutor(opt WorkerOpt, networkProviders map[pb.NetMode]bknet.Provider) (executor.Executor, error) { cmds := opt.CommandCandidates if cmds == nil { cmds = defaultCommandCandidates