Skip to content

Commit

Permalink
fix: data injection to return errors
Browse files Browse the repository at this point in the history
  • Loading branch information
phillebaba committed Jul 12, 2024
1 parent eca0c53 commit 6758b50
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 95 deletions.
165 changes: 80 additions & 85 deletions src/pkg/cluster/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"sort"
"strconv"
"strings"
"sync"
"time"

corev1 "k8s.io/api/core/v1"
Expand All @@ -32,12 +31,10 @@ import (

// HandleDataInjection waits for the target pod(s) to come up and inject the data into them
// todo: this currently requires kubectl but we should have enough k8s work to make this native now.
func (c *Cluster) HandleDataInjection(ctx context.Context, wg *sync.WaitGroup, data types.ZarfDataInjection, componentPath *layout.ComponentPaths, dataIdx int) {
defer wg.Done()
func (c *Cluster) HandleDataInjection(ctx context.Context, data types.ZarfDataInjection, componentPath *layout.ComponentPaths, dataIdx int) error {

Check warning on line 34 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L34

Added line #L34 was not covered by tests
injectionCompletionMarker := filepath.Join(componentPath.DataInjections, config.GetDataInjectionMarker())
if err := os.WriteFile(injectionCompletionMarker, []byte("🦄"), helpers.ReadWriteUser); err != nil {
message.WarnErrf(err, "Unable to create the data injection completion marker")
return
return fmt.Errorf("unable to create the data injection completion marker: %w", err)

Check warning on line 37 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L37

Added line #L37 was not covered by tests
}

tarCompressFlag := ""
Expand All @@ -59,103 +56,101 @@ func (c *Cluster) HandleDataInjection(ctx context.Context, wg *sync.WaitGroup, d
shell, shellArgs := exec.GetOSShell(exec.Shell{Windows: "cmd"})

if _, _, err := exec.Cmd(shell, append(shellArgs, "tar --version")...); err != nil {
message.WarnErr(err, "Unable to execute tar on this system. Please ensure it is installed and on your $PATH.")
return
return fmt.Errorf("unable to execute tar, ensure it is installed in the $PATH: %w", err)

Check warning on line 59 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L59

Added line #L59 was not covered by tests
}

iterator:
// The eternal loop because some data injections can take a very long time
for {
message.Debugf("Attempting to inject data into %s", data.Target)
source := filepath.Join(componentPath.DataInjections, filepath.Base(data.Target.Path))
if helpers.InvalidPath(source) {
// The path is likely invalid because of how we compose OCI components, add an index suffix to the filename
source = filepath.Join(componentPath.DataInjections, strconv.Itoa(dataIdx), filepath.Base(data.Target.Path))
select {
case <-ctx.Done():
return ctx.Err()
default:
message.Debugf("Attempting to inject data into %s", data.Target)
source := filepath.Join(componentPath.DataInjections, filepath.Base(data.Target.Path))

Check warning on line 68 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L63-L68

Added lines #L63 - L68 were not covered by tests
if helpers.InvalidPath(source) {
message.Warnf("Unable to find the data injection source path %s", source)
return
// The path is likely invalid because of how we compose OCI components, add an index suffix to the filename
source = filepath.Join(componentPath.DataInjections, strconv.Itoa(dataIdx), filepath.Base(data.Target.Path))
if helpers.InvalidPath(source) {
return fmt.Errorf("could not find the data injection source path %s", source)

Check warning on line 73 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L71-L73

Added lines #L71 - L73 were not covered by tests
}
}
}

target := podLookup{
Namespace: data.Target.Namespace,
Selector: data.Target.Selector,
Container: data.Target.Container,
}

// Wait until the pod we are injecting data into becomes available
pods := waitForPodsAndContainers(ctx, c.Clientset, target, podFilterByInitContainer)
if len(pods) < 1 {
continue
}
target := podLookup{
Namespace: data.Target.Namespace,
Selector: data.Target.Selector,
Container: data.Target.Container,

Check warning on line 80 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L77-L80

Added lines #L77 - L80 were not covered by tests
}

// Inject into all the pods
for _, pod := range pods {
// Try to use the embedded kubectl if we can
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", zarfCommand)
// Wait until the pod we are injecting data into becomes available
pods := waitForPodsAndContainers(ctx, c.Clientset, target, podFilterByInitContainer)
if len(pods) < 1 {
continue

Check warning on line 86 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L84-L86

Added lines #L84 - L86 were not covered by tests
}
kubectlCmd := fmt.Sprintf("%s exec -i -n %s %s -c %s ", kubectlBinPath, data.Target.Namespace, pod.Name, data.Target.Container)

// Note that each command flag is separated to provide the widest cross-platform tar support
tarCmd := fmt.Sprintf("tar -c %s -f -", tarCompressFlag)
untarCmd := fmt.Sprintf("tar -x %s -v -f - -C %s", tarCompressFlag, data.Target.Path)
// Inject into all the pods
for _, pod := range pods {

Check warning on line 90 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L90

Added line #L90 was not covered by tests
// Try to use the embedded kubectl if we can
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", zarfCommand)

Check warning on line 97 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L92-L97

Added lines #L92 - L97 were not covered by tests
}
kubectlCmd := fmt.Sprintf("%s exec -i -n %s %s -c %s ", kubectlBinPath, data.Target.Namespace, pod.Name, data.Target.Container)

Check warning on line 99 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L99

Added line #L99 was not covered by tests

// Must create the target directory before trying to change to it for untar
mkdirCmd := fmt.Sprintf("%s -- mkdir -p %s", kubectlCmd, data.Target.Path)
if err := exec.CmdWithPrint(shell, append(shellArgs, mkdirCmd)...); err != nil {
message.Warnf("Unable to create the data injection target directory %s in pod %s", data.Target.Path, pod.Name)
continue iterator
}
// Note that each command flag is separated to provide the widest cross-platform tar support
tarCmd := fmt.Sprintf("tar -c %s -f -", tarCompressFlag)
untarCmd := fmt.Sprintf("tar -x %s -v -f - -C %s", tarCompressFlag, data.Target.Path)

Check warning on line 103 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L102-L103

Added lines #L102 - L103 were not covered by tests

cpPodCmd := fmt.Sprintf("%s -C %s . | %s -- %s",
tarCmd,
source,
kubectlCmd,
untarCmd,
)

// Do the actual data injection
if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil {
message.Warnf("Error copying data into the pod %#v: %#v\n", pod.Name, err)
continue iterator
}
// Must create the target directory before trying to change to it for untar
mkdirCmd := fmt.Sprintf("%s -- mkdir -p %s", kubectlCmd, data.Target.Path)
if err := exec.CmdWithPrint(shell, append(shellArgs, mkdirCmd)...); err != nil {
return fmt.Errorf("unable to create the data injection target directory %s in pod %s: %w", data.Target.Path, pod.Name, err)

Check warning on line 108 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L106-L108

Added lines #L106 - L108 were not covered by tests
}

cpPodCmd := fmt.Sprintf("%s -C %s . | %s -- %s",
tarCmd,
source,
kubectlCmd,
untarCmd,
)

Check warning on line 116 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L111-L116

Added lines #L111 - L116 were not covered by tests

// Leave a marker in the target container for pods to track the sync action
cpPodCmd = fmt.Sprintf("%s -C %s %s | %s -- %s",
tarCmd,
componentPath.DataInjections,
config.GetDataInjectionMarker(),
kubectlCmd,
untarCmd,
)

if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil {
message.Warnf("Error saving the zarf sync completion file after injection into pod %#v\n", pod.Name)
continue iterator
// Do the actual data injection
if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil {
return fmt.Errorf("could not coy data ino the pod %s: %w", pod.Name, err)

Check warning on line 120 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L119-L120

Added lines #L119 - L120 were not covered by tests
}

// Leave a marker in the target container for pods to track the sync action
cpPodCmd = fmt.Sprintf("%s -C %s %s | %s -- %s",
tarCmd,
componentPath.DataInjections,
config.GetDataInjectionMarker(),
kubectlCmd,
untarCmd,
)

Check warning on line 130 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L124-L130

Added lines #L124 - L130 were not covered by tests

if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil {
return fmt.Errorf("could not save the Zarf sync completion file after injection into pod %s: %w", pod.Name, err)

Check warning on line 133 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L132-L133

Added lines #L132 - L133 were not covered by tests
}
}
}

// Do not look for a specific container after injection in case they are running an init container
podOnlyTarget := podLookup{
Namespace: data.Target.Namespace,
Selector: data.Target.Selector,
}
// Do not look for a specific container after injection in case they are running an init container
podOnlyTarget := podLookup{
Namespace: data.Target.Namespace,
Selector: data.Target.Selector,

Check warning on line 140 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L138-L140

Added lines #L138 - L140 were not covered by tests
}

// Block one final time to make sure at least one pod has come up and injected the data
// Using only the pod as the final selector because we don't know what the container name will be
// Still using the init container filter to make sure we have the right running pod
_ = waitForPodsAndContainers(ctx, c.Clientset, podOnlyTarget, podFilterByInitContainer)
// Block one final time to make sure at least one pod has come up and injected the data
// Using only the pod as the final selector because we don't know what the container name will be
// Still using the init container filter to make sure we have the right running pod
_ = waitForPodsAndContainers(ctx, c.Clientset, podOnlyTarget, podFilterByInitContainer)

Check warning on line 146 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L146

Added line #L146 was not covered by tests

// Cleanup now to reduce disk pressure
_ = os.RemoveAll(source)
// Cleanup now to reduce disk pressure
_ = os.RemoveAll(source)

Check warning on line 149 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L149

Added line #L149 was not covered by tests

// Return to stop the loop
return
// Return to stop the loop
return nil

Check warning on line 152 in src/pkg/cluster/data.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/cluster/data.go#L152

Added line #L152 was not covered by tests
}
}
}

Expand Down
21 changes: 11 additions & 10 deletions src/pkg/packager/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import (
"runtime"
"strconv"
"strings"
"sync"
"time"

"golang.org/x/sync/errgroup"

corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -288,7 +289,6 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp
hasCharts := len(component.Charts) > 0
hasManifests := len(component.Manifests) > 0
hasRepos := len(component.Repos) > 0
hasDataInjections := len(component.DataInjections) > 0
hasFiles := len(component.Files) > 0

onDeploy := component.Actions.OnDeploy
Expand Down Expand Up @@ -339,14 +339,11 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp
}
}

if hasDataInjections {
waitGroup := sync.WaitGroup{}
defer waitGroup.Wait()

for idx, data := range component.DataInjections {
waitGroup.Add(1)
go p.cluster.HandleDataInjection(ctx, &waitGroup, data, componentPath, idx)
}
g, gCtx := errgroup.WithContext(ctx)
for idx, data := range component.DataInjections {
g.Go(func() error {
return p.cluster.HandleDataInjection(gCtx, data, componentPath, idx)
})

Check warning on line 346 in src/pkg/packager/deploy.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/packager/deploy.go#L342-L346

Added lines #L342 - L346 were not covered by tests
}

if hasCharts || hasManifests {
Expand All @@ -359,6 +356,10 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp
return charts, fmt.Errorf("unable to run component after action: %w", err)
}

err = g.Wait()
if err != nil {
return nil, err

Check warning on line 361 in src/pkg/packager/deploy.go

View check run for this annotation

Codecov / codecov/patch

src/pkg/packager/deploy.go#L359-L361

Added lines #L359 - L361 were not covered by tests
}
return charts, nil
}

Expand Down

0 comments on commit 6758b50

Please sign in to comment.