diff --git a/src/cmd/package.go b/src/cmd/package.go index e8817bf60b..a62f11e1c7 100644 --- a/src/cmd/package.go +++ b/src/cmd/package.go @@ -133,9 +133,9 @@ var packageListCmd = &cobra.Command{ Short: lang.CmdPackageListShort, Run: func(cmd *cobra.Command, _ []string) { ctx := cmd.Context() - deployedZarfPackages, errs := common.NewClusterOrDie(ctx).GetDeployedZarfPackages(ctx) - if len(errs) > 0 && len(deployedZarfPackages) == 0 { - message.Fatalf(errs, lang.CmdPackageListNoPackageWarn) + deployedZarfPackages, err := common.NewClusterOrDie(ctx).GetDeployedZarfPackages(ctx) + if err != nil && len(deployedZarfPackages) == 0 { + message.Fatalf(err, lang.CmdPackageListNoPackageWarn) } // Populate a matrix of all the deployed packages @@ -157,8 +157,8 @@ var packageListCmd = &cobra.Command{ message.Table(header, packageData) // Print out any unmarshalling errors - if len(errs) > 0 { - message.Fatalf(errs, lang.CmdPackageListUnmarshalErr) + if err != nil { + message.Fatalf(err, lang.CmdPackageListUnmarshalErr) } }, } diff --git a/src/cmd/tools/crane.go b/src/cmd/tools/crane.go index b501aeac7a..3b750964d3 100644 --- a/src/cmd/tools/crane.go +++ b/src/cmd/tools/crane.go @@ -227,8 +227,8 @@ func pruneImages(cmd *cobra.Command, _ []string) error { return err } - zarfPackages, errs := c.GetDeployedZarfPackages(ctx) - if len(errs) > 0 { + zarfPackages, err := c.GetDeployedZarfPackages(ctx) + if err != nil { return lang.ErrUnableToGetPackages } diff --git a/src/pkg/cluster/zarf.go b/src/pkg/cluster/zarf.go index 4e558c6f67..4d01891f9d 100644 --- a/src/pkg/cluster/zarf.go +++ b/src/pkg/cluster/zarf.go @@ -7,6 +7,7 @@ package cluster import ( "context" "encoding/json" + "errors" "fmt" "strings" "time" @@ -23,31 +24,30 @@ import ( // GetDeployedZarfPackages gets metadata information about packages that have been deployed to the cluster. // We determine what packages have been deployed to the cluster by looking for specific secrets in the Zarf namespace. // Returns a list of DeployedPackage structs and a list of errors. -func (c *Cluster) GetDeployedZarfPackages(ctx context.Context) ([]types.DeployedPackage, []error) { - var deployedPackages = []types.DeployedPackage{} - var errorList []error +func (c *Cluster) GetDeployedZarfPackages(ctx context.Context) ([]types.DeployedPackage, error) { // Get the secrets that describe the deployed packages secrets, err := c.GetSecretsWithLabel(ctx, ZarfNamespaceName, ZarfPackageInfoLabel) if err != nil { - return deployedPackages, append(errorList, err) + return nil, err } - // Process the k8s secret into our internal structs + errs := []error{} + deployedPackages := []types.DeployedPackage{} for _, secret := range secrets.Items { - if strings.HasPrefix(secret.Name, config.ZarfPackagePrefix) { - var deployedPackage types.DeployedPackage - err := json.Unmarshal(secret.Data["data"], &deployedPackage) - // add the error to the error list - if err != nil { - errorList = append(errorList, fmt.Errorf("unable to unmarshal the secret %s/%s", secret.Namespace, secret.Name)) - } else { - deployedPackages = append(deployedPackages, deployedPackage) - } + if !strings.HasPrefix(secret.Name, config.ZarfPackagePrefix) { + continue + } + var deployedPackage types.DeployedPackage + // Process the k8s secret into our internal structs + err := json.Unmarshal(secret.Data["data"], &deployedPackage) + if err != nil { + errs = append(errs, fmt.Errorf("unable to unmarshal the secret %s/%s", secret.Namespace, secret.Name)) + continue } + deployedPackages = append(deployedPackages, deployedPackage) } - // TODO: If we move this function out of `internal` we should return a more standard singular error. - return deployedPackages, errorList + return deployedPackages, errors.Join(errs...) } // GetDeployedPackage gets the metadata information about the package name provided (if it exists in the cluster). diff --git a/src/pkg/cluster/zarf_test.go b/src/pkg/cluster/zarf_test.go index 69136a530f..b9451f3e72 100644 --- a/src/pkg/cluster/zarf_test.go +++ b/src/pkg/cluster/zarf_test.go @@ -5,10 +5,18 @@ package cluster import ( + "context" + "encoding/json" + "strings" "testing" + "github.com/defenseunicorns/zarf/src/config" + "github.com/defenseunicorns/zarf/src/pkg/k8s" "github.com/defenseunicorns/zarf/src/types" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" ) // TestPackageSecretNeedsWait verifies that Zarf waits for webhooks to complete correctly. @@ -191,3 +199,51 @@ func TestPackageSecretNeedsWait(t *testing.T) { }) } } + +func TestGetDeployedPackage(t *testing.T) { + t.Parallel() + ctx := context.Background() + c := &Cluster{&k8s.K8s{Clientset: fake.NewSimpleClientset()}} + + packages := []types.DeployedPackage{ + {Name: "package1"}, + {Name: "package2"}, + } + + for _, p := range packages { + b, err := json.Marshal(p) + require.NoError(t, err) + data := map[string][]byte{ + "data": b, + } + secret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: strings.Join([]string{config.ZarfPackagePrefix, p.Name}, ""), + Namespace: "zarf", + Labels: map[string]string{ + ZarfPackageInfoLabel: p.Name, + }, + }, + Data: data, + } + c.Clientset.CoreV1().Secrets("zarf").Create(ctx, &secret, metav1.CreateOptions{}) + actual, err := c.GetDeployedPackage(ctx, p.Name) + require.NoError(t, err) + require.Equal(t, p, *actual) + } + + nonPackageSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "hello-world", + Namespace: "zarf", + Labels: map[string]string{ + ZarfPackageInfoLabel: "whatever", + }, + }, + } + c.Clientset.CoreV1().Secrets("zarf").Create(ctx, &nonPackageSecret, metav1.CreateOptions{}) + + actualList, err := c.GetDeployedZarfPackages(ctx) + require.NoError(t, err) + require.ElementsMatch(t, packages, actualList) +}