Skip to content

Commit

Permalink
fix: normalize Zarf command handling in Zarf (#2050)
Browse files Browse the repository at this point in the history
## Description

This Pr normalizes Zarf command execution in Zarf so that the patterns
work correctly when used as a library

## Related Issue

Relates to #1814
Fixes #2026

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Other (security config, docs update, etc)

## Checklist before merging

- [x] Test, docs, adr added or updated as needed
- [x] [Contributor Guide
Steps](https://github.com/defenseunicorns/zarf/blob/main/CONTRIBUTING.md#developer-workflow)
followed
  • Loading branch information
Racer159 authored Oct 4, 2023
1 parent 1c5f3f9 commit 43783f5
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/cmd/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ func findInitPackage(initPackageName string) (string, error) {
}

// Next, look for the init package in the executable directory
zarfBinPath, err := utils.GetFinalExecutablePath()
binaryPath, err := utils.GetFinalExecutablePath()
if err != nil {
return "", err
}
executableDir := path.Dir(zarfBinPath)
executableDir := path.Dir(binaryPath)
if !utils.InvalidPath(filepath.Join(executableDir, initPackageName)) {
return filepath.Join(executableDir, initPackageName), nil
}
Expand Down
4 changes: 4 additions & 0 deletions src/cmd/tools/crane.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func zarfCraneCatalog(cranePlatformOptions *[]crane.Option) *cobra.Command {
}

if tunnel != nil {
message.Notef(lang.CmdToolsRegistryTunnel, registryEndpoint, zarfState.RegistryInfo.Address)
defer tunnel.Close()
}

Expand Down Expand Up @@ -186,6 +187,8 @@ func zarfCraneInternalWrapper(commandToWrap func(*[]crane.Option) *cobra.Command
}

if tunnel != nil {
message.Notef(lang.CmdToolsRegistryTunnel, tunnel.Endpoint(), zarfState.RegistryInfo.Address)

defer tunnel.Close()

givenAddress := fmt.Sprintf("%s/", zarfState.RegistryInfo.Address)
Expand Down Expand Up @@ -229,6 +232,7 @@ func pruneImages(_ *cobra.Command, _ []string) error {
}

if tunnel != nil {
message.Notef(lang.CmdToolsRegistryTunnel, registryEndpoint, zarfState.RegistryInfo.Address)
defer tunnel.Close()
}

Expand Down
1 change: 1 addition & 0 deletions src/config/lang/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ const (

CmdToolsRegistryShort = "Tools for working with container registries using go-containertools"
CmdToolsRegistryZarfState = "Retrieving registry information from Zarf state"
CmdToolsRegistryTunnel = "Opening a tunnel from %s locally to %s in the cluster"

CmdToolsRegistryCatalogExample = `
# list the repos internal to Zarf
Expand Down
4 changes: 2 additions & 2 deletions src/internal/api/packages/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func FindInitStream(w http.ResponseWriter, _ *http.Request) {
done := make(chan bool)
go func() {
// stream init packages in the execution directory
if execBin, err := utils.GetFinalExecutablePath(); err == nil {
streamDirPackages(filepath.Dir(execBin), packager.ZarfInitPattern, w)
if binaryPath, err := utils.GetFinalExecutablePath(); err == nil {
streamDirPackages(filepath.Dir(binaryPath), packager.ZarfInitPattern, w)
} else {
streamError(err, w)
}
Expand Down
4 changes: 2 additions & 2 deletions src/internal/cluster/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ iterator:
// Inject into all the pods
for _, pod := range pods {
// Try to use the embedded kubectl if we can
zarfBinPath, err := utils.GetFinalExecutablePath()
zarfCommand, err := utils.GetFinalExecutableCommand()
kubectlBinPath := "kubectl"
if err != nil {
message.Warnf("Unable to get the zarf executable path, falling back to host kubectl: %s", err)
} else {
kubectlBinPath = fmt.Sprintf("%s tools kubectl", zarfBinPath)
kubectlBinPath = fmt.Sprintf("%s tools kubectl", zarfCommand)
}
kubectlCmd := fmt.Sprintf("%s exec -i -n %s %s -c %s ", kubectlBinPath, data.Target.Namespace, pod.Name, data.Target.Container)

Expand Down
13 changes: 2 additions & 11 deletions src/pkg/packager/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ package packager
import (
"context"
"fmt"
"os"
"regexp"
"runtime"
"strings"
"time"

"github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/internal/packager/template"
"github.com/defenseunicorns/zarf/src/pkg/message"
"github.com/defenseunicorns/zarf/src/pkg/utils"
Expand Down Expand Up @@ -209,20 +207,13 @@ func convertWaitToCmd(wait types.ZarfComponentActionWait, timeout *int) (string,

// Perform some basic string mutations to make commands more useful.
func actionCmdMutation(cmd string, shellPref types.ZarfComponentActionShell) (string, error) {
binaryPath, err := os.Executable()
zarfCommand, err := utils.GetFinalExecutableCommand()
if err != nil {
return cmd, err
}

binaryPath = fmt.Sprintf("%s %s", binaryPath, config.ActionsCommandZarfPrefix)

// If a library user has chosen to override config to use system Zarf instead, reset the binary path.
if config.ActionsUseSystemZarf {
binaryPath = "zarf"
}

// Try to patch the zarf binary path in case the name isn't exactly "./zarf".
cmd = strings.ReplaceAll(cmd, "./zarf ", binaryPath+" ")
cmd = strings.ReplaceAll(cmd, "./zarf ", zarfCommand+" ")

// Make commands 'more' compatible with Windows OS PowerShell
if runtime.GOOS == "windows" && (exec.IsPowershell(shellPref.Windows) || shellPref.Windows == "") {
Expand Down
25 changes: 23 additions & 2 deletions src/pkg/utils/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"regexp"
"strings"

"github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/pkg/message"
"github.com/defenseunicorns/zarf/src/pkg/utils/helpers"
"github.com/defenseunicorns/zarf/src/types"
Expand Down Expand Up @@ -254,7 +255,7 @@ func CreatePathAndCopy(source string, destination string) error {
return CreateFile(destination)
}

// GetFinalExecutablePath returns the absolute path to the Zarf executable, following any symlinks along the way.
// GetFinalExecutablePath returns the absolute path to the current executable, following any symlinks along the way.
func GetFinalExecutablePath() (string, error) {
message.Debug("utils.GetExecutablePath()")

Expand All @@ -263,11 +264,31 @@ func GetFinalExecutablePath() (string, error) {
return "", err
}

// In case the binary is symlinked somewhere else, get the final destination!!
// In case the binary is symlinked somewhere else, get the final destination
linkedPath, err := filepath.EvalSymlinks(binaryPath)
return linkedPath, err
}

// GetFinalExecutableCommand returns the final path to the Zarf executable including and library prefixes and overrides.
func GetFinalExecutableCommand() (string, error) {
// In case the binary is symlinked somewhere else, get the final destination
zarfCommand, err := GetFinalExecutablePath()
if err != nil {
return zarfCommand, err
}

if config.ActionsCommandZarfPrefix != "" {
zarfCommand = fmt.Sprintf("%s %s", zarfCommand, config.ActionsCommandZarfPrefix)
}

// If a library user has chosen to override config to use system Zarf instead, reset the binary path.
if config.ActionsUseSystemZarf {
zarfCommand = "zarf"
}

return zarfCommand, err
}

// SplitFile splits a file into multiple parts by the given size.
func SplitFile(path string, chunkSizeBytes int) (chunks [][]byte, sha256sum string, err error) {
var file []byte
Expand Down
19 changes: 11 additions & 8 deletions src/pkg/utils/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"time"

"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
"github.com/defenseunicorns/zarf/src/types"

"github.com/defenseunicorns/zarf/src/config/lang"
"github.com/defenseunicorns/zarf/src/pkg/message"
Expand Down Expand Up @@ -46,8 +47,8 @@ func ExecuteWait(waitTimeout, waitNamespace, condition, kind, identifier string,
waitType = "condition="
}

// Get the Zarf executable path.
zarfBinPath, err := GetFinalExecutablePath()
// Get the Zarf command configuration.
zarfCommand, err := GetFinalExecutableCommand()
if err != nil {
message.Fatal(err, lang.CmdToolsWaitForErrZarfPath)
}
Expand All @@ -73,6 +74,9 @@ func ExecuteWait(waitTimeout, waitNamespace, condition, kind, identifier string,
existMsg := fmt.Sprintf("Waiting for %s%s%s to exist.", kind, identifierMsg, namespaceMsg)
spinner := message.NewProgressSpinner(existMsg)

// Get the OS shell to execute commands in
shell, shellArgs := exec.GetOSShell(types.ZarfComponentActionShell{Windows: "cmd"})

defer spinner.Stop()

for {
Expand All @@ -86,8 +90,8 @@ func ExecuteWait(waitTimeout, waitNamespace, condition, kind, identifier string,
default:
spinner.Updatef(existMsg)
// Check if the resource exists.
args := []string{"tools", "kubectl", "get", "-n", waitNamespace, kind, identifier}
if stdout, stderr, err := exec.Cmd(zarfBinPath, args...); err != nil {
zarfKubectlGet := fmt.Sprintf("%s tools kubectl get -n %s %s %s", zarfCommand, waitNamespace, kind, identifier)
if stdout, stderr, err := exec.Cmd(shell, shellArgs, zarfKubectlGet); err != nil {
message.Debug(stdout, stderr, err)
continue
}
Expand All @@ -101,12 +105,11 @@ func ExecuteWait(waitTimeout, waitNamespace, condition, kind, identifier string,

spinner.Updatef(conditionMsg)
// Wait for the resource to meet the given condition.
args = []string{"tools", "kubectl", "wait", "-n", waitNamespace,
kind, identifier, "--for", waitType + condition,
"--timeout=" + waitTimeout}
zarfKubectlWait := fmt.Sprintf("%s tools kubectl wait -n %s %s %s --for %s%s --timeout=%s",
zarfCommand, waitNamespace, kind, identifier, waitType, condition, waitTimeout)

// If there is an error, log it and try again.
if stdout, stderr, err := exec.Cmd(zarfBinPath, args...); err != nil {
if stdout, stderr, err := exec.Cmd(shell, shellArgs, zarfKubectlWait); err != nil {
message.Debug(stdout, stderr, err)
continue
}
Expand Down

0 comments on commit 43783f5

Please sign in to comment.