From 893d8f087ce8aaec6ecdcab09444c26a60a11d1b Mon Sep 17 00:00:00 2001 From: Denis Romanenko Date: Mon, 3 Jun 2024 12:53:08 +0300 Subject: [PATCH] + Signed-off-by: Denis Romanenko --- internal/dhctl/cmd/bootstrap.go | 12 +++++- internal/dhctl/cmd/dhctl.go | 7 +-- internal/dhctl/cmd/flags.go | 37 ---------------- internal/dhctl/cmd/utils.go | 63 +++++++++++++++++++++++++++ internal/dhctl/image/image.go | 76 +++++++++++++++++++++++++++------ 5 files changed, 141 insertions(+), 54 deletions(-) create mode 100644 internal/dhctl/cmd/utils.go diff --git a/internal/dhctl/cmd/bootstrap.go b/internal/dhctl/cmd/bootstrap.go index ee45036..b4e7e93 100644 --- a/internal/dhctl/cmd/bootstrap.go +++ b/internal/dhctl/cmd/bootstrap.go @@ -50,9 +50,17 @@ func parseAndValidateParameters(cmd *cobra.Command, args []string) error { } func bootstrap(cmd *cobra.Command, args []string) error { - ctx := buildInstallerContext() - return image.PullInstallerImage(ctx) + img := image.NewImage(buildContext(), TempDir, ImageTag, os.Args[1:], getDhctlEnvs()) + err := img.Pull() + if err != nil { + return err + } + err = img.Run() + if err != nil { + return err + } + return nil } func cleanup(cmd *cobra.Command, args []string) error { diff --git a/internal/dhctl/cmd/dhctl.go b/internal/dhctl/cmd/dhctl.go index 4b96417..db51616 100644 --- a/internal/dhctl/cmd/dhctl.go +++ b/internal/dhctl/cmd/dhctl.go @@ -14,9 +14,10 @@ valid license for any commercial version of the Deckhouse Kubernetes Platform. func NewCommand() *cobra.Command { dhctlCmd := &cobra.Command{ - Use: "i", - Short: "run Deckhouse installer tool", - Long: "Run Deckhouse installer tool.\n" + licenceNote, + Use: "i", + Aliases: []string{"dhctl"}, + Short: "run Deckhouse installer tool", + Long: "Run Deckhouse installer tool.\n" + licenceNote, } dhctlCmd.AddCommand( diff --git a/internal/dhctl/cmd/flags.go b/internal/dhctl/cmd/flags.go index 97f4aa8..46af9e8 100644 --- a/internal/dhctl/cmd/flags.go +++ b/internal/dhctl/cmd/flags.go @@ -18,12 +18,9 @@ import ( "os" "path/filepath" - "github.com/google/go-containerregistry/pkg/authn" "github.com/spf13/pflag" "github.com/deckhouse/deckhouse-cli/internal/dhctl/cmd/app" - "github.com/deckhouse/deckhouse-cli/internal/dhctl/image" - "github.com/deckhouse/deckhouse-cli/internal/mirror/contexts" ) const ( @@ -101,37 +98,3 @@ func addRegistryFlags(flagSet *pflag.FlagSet) { "Interact with registries over HTTP.", ) } - -func getSourceRegistryAuthProvider() authn.Authenticator { - if RegistryLogin != "" { - return authn.FromConfig(authn.AuthConfig{ - Username: RegistryLogin, - Password: RegistryPassword, - }) - } - - if LicenseToken != "" { - return authn.FromConfig(authn.AuthConfig{ - Username: "license-token", - Password: LicenseToken, - }) - } - - return authn.Anonymous -} - -func buildInstallerContext() *image.InstallerContext { - ctx := &image.InstallerContext{ - BaseContext: contexts.BaseContext{ - Insecure: Insecure, - SkipTLSVerification: TLSSkipVerify, - DeckhouseRegistryRepo: RegistryRepo, - RegistryAuth: getSourceRegistryAuthProvider(), - UnpackedImagesPath: TempDir, - }, - Args: os.Args[1:], - ImageTag: ImageTag, - TempDir: TempDir, - } - return ctx -} diff --git a/internal/dhctl/cmd/utils.go b/internal/dhctl/cmd/utils.go new file mode 100644 index 0000000..d46cc33 --- /dev/null +++ b/internal/dhctl/cmd/utils.go @@ -0,0 +1,63 @@ +// Copyright 2024 Flant JSC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dhctl + +import ( + "os" + "strings" + + "github.com/google/go-containerregistry/pkg/authn" + + "github.com/deckhouse/deckhouse-cli/internal/mirror/contexts" +) + +func getSourceRegistryAuthProvider() authn.Authenticator { + if RegistryLogin != "" { + return authn.FromConfig(authn.AuthConfig{ + Username: RegistryLogin, + Password: RegistryPassword, + }) + } + + if LicenseToken != "" { + return authn.FromConfig(authn.AuthConfig{ + Username: "license-token", + Password: LicenseToken, + }) + } + return authn.Anonymous +} + +func buildContext() *contexts.BaseContext { + ctx := &contexts.BaseContext{ + Insecure: Insecure, + SkipTLSVerification: TLSSkipVerify, + DeckhouseRegistryRepo: RegistryRepo, + RegistryAuth: getSourceRegistryAuthProvider(), + UnpackedImagesPath: TempDir, + } + return ctx +} + +func getDhctlEnvs() map[string]string { + ret := make(map[string]string) + for _, s := range os.Environ() { + pair := strings.SplitN(s, "=", 2) + if strings.HasPrefix(pair[0], "DHCTL_") { + ret[pair[0]] = pair[1] + } + } + return ret +} diff --git a/internal/dhctl/image/image.go b/internal/dhctl/image/image.go index fdb8691..952fbc1 100644 --- a/internal/dhctl/image/image.go +++ b/internal/dhctl/image/image.go @@ -20,8 +20,10 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" "slices" + "syscall" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" @@ -32,24 +34,34 @@ import ( "github.com/deckhouse/deckhouse-cli/internal/mirror/util/log" ) -// InstallerContext holds data related to pending mirroring-from-registry operation. -type InstallerContext struct { - contexts.BaseContext - Args []string - ImageTag string - TempDir string +type Image struct { + ctx *contexts.BaseContext + args []string + imageTag string + tempDir string + envs map[string]string } -func PullInstallerImage(ctx *InstallerContext) error { - nameOpts, remoteOpts := auth.MakeRemoteRegistryRequestOptions(ctx.RegistryAuth, ctx.Insecure, ctx.SkipTLSVerification) - imageRef := fmt.Sprintf("%s/%s:%s", ctx.DeckhouseRegistryRepo, "install", ctx.ImageTag) +func NewImage(ctx *contexts.BaseContext, tempDir string, imageTag string, args []string, envs map[string]string) *Image { + return &Image{ + ctx: ctx, + tempDir: tempDir, + imageTag: imageTag, + args: args, + envs: envs, + } +} + +func (img *Image) Pull() error { + nameOpts, remoteOpts := auth.MakeRemoteRegistryRequestOptions(img.ctx.RegistryAuth, img.ctx.Insecure, img.ctx.SkipTLSVerification) + imageRef := fmt.Sprintf("%s/%s:%s", img.ctx.DeckhouseRegistryRepo, "install", img.imageTag) ref, err := name.ParseReference(imageRef, nameOpts...) if err != nil { return err } log.InfoF("Pulling %s...\n", imageRef) - img, err := remote.Image(ref, remoteOpts...) + image, err := remote.Image(ref, remoteOpts...) if err != nil { if errorutil.IsImageNotFoundError(err) { return fmt.Errorf("⚠️ %s Not found in registry", imageRef) @@ -57,7 +69,7 @@ func PullInstallerImage(ctx *InstallerContext) error { return fmt.Errorf("pull image %s metadata: %w", imageRef, err) } - layers, err := img.Layers() + layers, err := image.Layers() if err != nil { return err } @@ -75,7 +87,7 @@ func PullInstallerImage(ctx *InstallerContext) error { return err } - err = writeAndUnpackLayer(r, ctx.TempDir, digest.String()) + err = writeAndUnpackLayer(r, img.tempDir, digest.String()) if err != nil { return err } @@ -122,3 +134,43 @@ func writeAndUnpackLayer(r io.ReadCloser, targetDir, filename string) error { } return nil } + +func (img *Image) Run() error { + log.InfoF("Running %s...\n", img.tempDir) + //Hold onto old root + oldrootHandle, err := os.Open("/") + if err != nil { + panic(err) + } + defer oldrootHandle.Close() + + cmd := exec.Command(img.args[0], img.args[1:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + //New Root time + err = syscall.Chdir(img.tempDir) + if err != nil { + return err + } + + err = syscall.Chroot(img.tempDir) + if err != nil { + return err + } + + err = cmd.Run() + if err != nil { + return err + } + + //Go back to old root + //So that we can clean up the temp dir + err = syscall.Fchdir(int(oldrootHandle.Fd())) + if err != nil { + return err + } + + return syscall.Chroot(".") +}