Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail when package architecture doesn't match cluster architecture #1495

Merged
merged 86 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
394b871
Add check for mismatched architectures for zarf init
Mar 28, 2023
9ed49ee
Merge branch 'main' into zarf-init-arch
Mar 28, 2023
dc2e5e7
Update test to use UnknownVersion as the init package version
Mar 29, 2023
5be35bb
Merge branch 'main' into zarf-init-arch
Mar 29, 2023
b47750a
Update test to use --architecture flag with zarf init
Mar 29, 2023
6d194c1
Merge branch 'main' into zarf-init-arch
Mar 29, 2023
e88fdf2
Update verifyArchitecture function to handle appliance mode
Mar 29, 2023
64cf995
Add mismatched arch error message to lang package
Mar 29, 2023
3616ef9
Use the Contains function in test to check for error message
Mar 29, 2023
ffecbf9
Still trying to capture and validate the error message properly
Mar 30, 2023
edd5b1f
Still messing with error output
Mar 30, 2023
1d4773a
Format error message before checking for it
Mar 30, 2023
77b187a
Merge branch 'main' into zarf-init-arch
Mar 30, 2023
e825780
Remove use of TrimSpace for zarf version
Mar 30, 2023
2b93e26
Use arch field from Packager struct to get init package architecture
Mar 30, 2023
f560f18
Go back to using NewClusterOrDie
Mar 30, 2023
3cc8687
Merge branch 'main' into zarf-init-arch
Mar 30, 2023
27b5e04
Revert back to getting package arch from package name
Mar 31, 2023
db250f9
Merge branch 'main' into zarf-init-arch
Mar 31, 2023
d3bd641
Merge branch 'main' into zarf-init-arch
Apr 3, 2023
4792b24
Merge branch 'main' into zarf-init-arch
Apr 4, 2023
129c298
Merge branch 'main' into zarf-init-arch
Apr 4, 2023
e63427d
Merge branch 'main' into zarf-init-arch
Apr 5, 2023
3cad480
Refactor package architecture validation
Apr 6, 2023
adfc0f4
Merge branch 'main' into zarf-init-arch
Apr 6, 2023
6c1aeb3
Put package path before flags in package create for test
Apr 6, 2023
d530e46
Check if the package is using k8s
Apr 6, 2023
267ab52
Add trailing forward slash to test package paths
Apr 6, 2023
58aceb9
Remove use of filepath Join function for test package paths
Apr 6, 2023
ccb4fdc
Use separate directories to store test zarf package configs
Apr 6, 2023
ebc6f6e
Fix typo and change test package paths
Apr 6, 2023
5a6c986
Use test packages with k8s resources
Apr 6, 2023
b677e64
Merge branch 'main' into zarf-init-arch
Apr 12, 2023
b7aaeae
Update check for appliance mode init package
Apr 12, 2023
6438a64
Merge branch 'main' into zarf-init-arch
Apr 12, 2023
4d386e8
Merge branch 'main' into zarf-init-arch
Apr 12, 2023
881e2db
Merge branch 'main' into zarf-init-arch
Apr 13, 2023
af2753f
It works on my machine
Apr 13, 2023
b1d09ba
Update expected error message to handle both init and deploy failures…
Apr 13, 2023
c09dcf8
Remove unused function parameter
Apr 13, 2023
045fbdb
Trying to handle various package deployment scenarios
Apr 13, 2023
e57f6e1
Remove setup of client connection
Apr 13, 2023
fb96ba4
Put the arch check back in the conditionals
Apr 13, 2023
b554b50
Merge branch 'main' into zarf-init-arch
Apr 17, 2023
3f0a449
Merge branch 'main' into zarf-init-arch
Apr 18, 2023
2214fd1
Remove cluster connection check
Apr 18, 2023
960ba63
Handle packages with k8s resources
Apr 19, 2023
fb43fac
Merge branch 'main' into zarf-init-arch
Apr 19, 2023
93bb34d
Set spinner parameter to false in NewClusterWithWait
Apr 19, 2023
3076a18
Add test case to verify packages without k8s resources
Apr 19, 2023
bd6d466
Merge branch 'main' into zarf-init-arch
Apr 19, 2023
9c604c9
Consider successful check if applianceMode returns no error
Apr 19, 2023
830ea45
Merge branch 'main' into zarf-init-arch
Apr 19, 2023
05c1375
Merge branch 'main' into zarf-init-arch
Apr 21, 2023
a5259b3
Merge branch 'main' into zarf-init-arch
Apr 21, 2023
2a34e73
Merge branch 'main' into zarf-init-arch
Racer159 Apr 21, 2023
cf3198c
Merge branch 'main' into zarf-init-arch
Apr 23, 2023
8fb0bd2
Update cluster connection method
Apr 23, 2023
cff098f
Merge branch 'main' into zarf-init-arch
Apr 24, 2023
4ec866c
Merge branch 'main' into zarf-init-arch
Apr 25, 2023
bdabd2a
Add architecture validation to k3s package
Apr 25, 2023
fec42f9
Add name of constant DefaultTimeout to comment to fix linting error
Apr 25, 2023
b4f9776
Add test case for zarf init in appliance mode
Apr 25, 2023
219c272
Add appliance mode test case to zarf_init_test
Apr 25, 2023
df8a6a9
Remove echo statement from arch check in k3s package actions
Apr 25, 2023
27eb45d
Merge branch 'main' into zarf-init-arch
Apr 28, 2023
dd40266
Merge branch 'main' into zarf-init-arch
May 1, 2023
d7e9cdc
Update action cmd in k3s package for checking arch
May 1, 2023
1768191
Check for exit code 0 when running actions
May 1, 2023
0a25418
Revert "Check for exit code 0 when running actions"
May 2, 2023
419ecdf
Merge branch 'main' into zarf-init-arch
May 2, 2023
a8ed1d7
Merge branch 'main' into zarf-init-arch
May 4, 2023
f5891c4
Fix arch check in k3s package
May 4, 2023
467a426
Merge branch 'main' into zarf-init-arch
Racer159 May 8, 2023
51945c5
Use target system instead of target cluster in k3s package error message
lucasrod16 May 8, 2023
7f50d0c
Remove MismatchedArch field from ZarfE2ETest struct
lucasrod16 May 8, 2023
3b84337
Update SetMismatchedArch test helper function to GetMismatchedArch
lucasrod16 May 8, 2023
2662ff4
Update function name when setting mismatchedArch var in init test
lucasrod16 May 8, 2023
547cac8
Use NewCluster function to check if for access to k8s cluster
lucasrod16 May 8, 2023
99a20b5
Swap CmdWithContext function with ExecZarfCommand function in init test
lucasrod16 May 8, 2023
049f2a6
Update function name for getting mismatched arch in mismatched arch test
May 8, 2023
ffce5dc
Remove context.WithTimeout function from init test
May 8, 2023
4dbdf1a
Check that mismatched arch test return expected error message
May 8, 2023
283ea08
Update error message in k3s package
May 8, 2023
202c672
Merge branch 'main' into zarf-init-arch
May 8, 2023
abaeaa1
Merge branch 'main' into zarf-init-arch
Racer159 May 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/distros/k3s/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ components:
- source: https://github.com/k3s-io/k3s/releases/download/v1.24.1+k3s1/k3s-airgap-images-amd64.tar.zst
shasum: 6736f9fa4d5754d60b0508bafb2f888170cb99a2d93a3a1617a919ca4ee74034
target: /var/lib/rancher/k3s/agent/images/k3s.tar.zst
actions:
onDeploy:
before:
- cmd: if [ "$(arch)" != "x86_64" ]; then echo "this package architecture is amd64, but the target system has a different architecture. These architectures must be the same" && exit 1; fi
description: Check that the host architecture matches the package architecture
maxRetries: 0

# ARM-64 version of the K3s stack
- name: k3s
Expand All @@ -51,3 +57,9 @@ components:
- source: https://github.com/k3s-io/k3s/releases/download/v1.24.1+k3s1/k3s-airgap-images-arm64.tar.zst
shasum: 12029e4bbfecfa16942345aeac798f4790e568a7202c2b85ee068d7b4756ba04
target: /var/lib/rancher/k3s/agent/images/k3s.tar.zst
actions:
onDeploy:
before:
- cmd: if [ "$(arch)" != "arm64" ]; then echo "this package architecture is arm64, but the target system has a different architecture. These architectures must be the same" && exit 1; fi
description: Check that the host architecture matches the package architecture
maxRetries: 0
3 changes: 1 addition & 2 deletions src/cmd/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"errors"
"os"
"regexp"
"time"

"github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/config/lang"
Expand All @@ -30,7 +29,7 @@ var destroyCmd = &cobra.Command{
Short: lang.CmdDestroyShort,
Long: lang.CmdDestroyLong,
Run: func(cmd *cobra.Command, args []string) {
c, err := cluster.NewClusterWithWait(30*time.Second, true)
c, err := cluster.NewClusterWithWait(cluster.DefaultTimeout, true)
if err != nil {
message.Fatalf(err, lang.ErrNoClusterConnection)
}
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 @@ -225,6 +225,7 @@ zarf init --git-push-password={PASSWORD} --git-push-username={USERNAME} --git-ur
CmdPackageDeployFlagShasum = "Shasum of the package to deploy. Required if deploying a remote package and \"--insecure\" is not provided"
CmdPackageDeployFlagSget = "Path to public sget key file for remote packages signed via cosign"
CmdPackageDeployFlagPublicKey = "Path to public key file for validating signed packages"
CmdPackageDeployValidateArchitectureErr = "this package architecture is %s, but the target cluster has the %s architecture. These architectures must be the same"

CmdPackageInspectFlagSbom = "View SBOM contents while inspecting the package"
CmdPackageInspectFlagSbomOut = "Specify an output directory for the SBOMs from the inspected Zarf package"
Expand Down
5 changes: 3 additions & 2 deletions src/internal/cluster/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ type Cluster struct {
}

const (
defaultTimeout = 30 * time.Second
// DefaultTimeout is the default time to wait for a cluster to be ready.
DefaultTimeout = 30 * time.Second
lucasrod16 marked this conversation as resolved.
Show resolved Hide resolved
agentLabel = "zarf.dev/agent"
)

Expand All @@ -28,7 +29,7 @@ var labels = k8s.Labels{

// NewClusterOrDie creates a new cluster instance and waits up to 30 seconds for the cluster to be ready or throws a fatal error.
func NewClusterOrDie() *Cluster {
c, err := NewClusterWithWait(defaultTimeout, true)
c, err := NewClusterWithWait(DefaultTimeout, true)
lucasrod16 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
message.Fatalf(err, "Failed to connect to cluster")
}
Expand Down
6 changes: 3 additions & 3 deletions src/internal/cluster/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func ServiceInfoFromNodePortURL(nodePortURL string) (*ServiceInfo, error) {
return nil, fmt.Errorf("node port services should use the port range 30000-32767")
}

kube, err := k8s.NewWithWait(message.Debugf, labels, defaultTimeout)
kube, err := k8s.NewWithWait(message.Debugf, labels, DefaultTimeout)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -187,7 +187,7 @@ func ServiceInfoFromServiceURL(serviceURL string) (*ServiceInfo, error) {
func NewTunnel(namespace, resourceType, resourceName string, local, remote int) (*Tunnel, error) {
message.Debugf("tunnel.NewTunnel(%s, %s, %s, %d, %d)", namespace, resourceType, resourceName, local, remote)

kube, err := k8s.NewWithWait(message.Debugf, labels, defaultTimeout)
kube, err := k8s.NewWithWait(message.Debugf, labels, DefaultTimeout)
if err != nil {
return &Tunnel{}, err
}
Expand Down Expand Up @@ -410,7 +410,7 @@ func (tunnel *Tunnel) establish() (string, error) {
message.Debug(spinnerMessage)
}

kube, err := k8s.NewWithWait(message.Debugf, labels, defaultTimeout)
kube, err := k8s.NewWithWait(message.Debugf, labels, DefaultTimeout)
if err != nil {
return "", fmt.Errorf("unable to connect to the cluster: %w", err)
}
Expand Down
19 changes: 19 additions & 0 deletions src/pkg/packager/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"strings"

"github.com/AlecAivazis/survey/v2"
"github.com/defenseunicorns/zarf/src/config/lang"
"github.com/defenseunicorns/zarf/src/internal/cluster"
"github.com/defenseunicorns/zarf/src/internal/packager/sbom"
"github.com/defenseunicorns/zarf/src/types"
Expand Down Expand Up @@ -443,6 +444,24 @@ func (p *Packager) validatePackageChecksums() error {
return nil
}

// validatePackageArchitecture validates that the package architecture matches the target cluster architecture.
func (p *Packager) validatePackageArchitecture() error {
// Attempt to connect to a cluster to get the architecture.
if cluster, err := cluster.NewCluster(); err == nil {
clusterArch, err := cluster.Kube.GetArchitecture()
if err != nil {
return err
}

// Check if the package architecture and the cluster architecture are the same.
if p.arch != clusterArch {
return fmt.Errorf(lang.CmdPackageDeployValidateArchitectureErr, p.arch, clusterArch)
}
}

return nil
}

func (p *Packager) validatePackageSignature(publicKeyPath string) error {

// If the insecure flag was provided, ignore the signature validation
Expand Down
6 changes: 5 additions & 1 deletion src/pkg/packager/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func (p *Packager) Deploy() error {
return fmt.Errorf("unable to load the Zarf Package: %w", err)
}

if err := p.validatePackageArchitecture(); err != nil {
return err
}

if err := p.validatePackageSignature(p.cfg.DeployOpts.PublicKeyPath); err != nil {
return err
}
Expand Down Expand Up @@ -218,7 +222,7 @@ func (p *Packager) deployComponent(component types.ZarfComponent, noImgChecksum

// Make sure we have access to the cluster
if p.cluster == nil {
p.cluster, err = cluster.NewClusterWithWait(30*time.Second, true)
p.cluster, err = cluster.NewClusterWithWait(cluster.DefaultTimeout, true)
if err != nil {
return charts, fmt.Errorf("unable to connect to the Kubernetes cluster: %w", err)
}
Expand Down
3 changes: 1 addition & 2 deletions src/pkg/packager/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"strings"
"time"

"github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/internal/cluster"
Expand Down Expand Up @@ -64,7 +63,7 @@ func (p *Packager) Remove(packageName string) (err error) {
if requiresCluster {
// If we need the cluster, connect to it and pull the package secret
if p.cluster == nil {
p.cluster, err = cluster.NewClusterWithWait(30*time.Second, true)
p.cluster, err = cluster.NewClusterWithWait(cluster.DefaultTimeout, true)
if err != nil {
return fmt.Errorf("unable to connect to the Kubernetes cluster: %w", err)
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,14 @@ func (e2e *ZarfE2ETest) CleanFiles(files ...string) {
_ = os.RemoveAll(file)
}
}

// GetMismatchedArch determines what architecture our tests are running on,
// and returns the opposite architecture.
func (e2e *ZarfE2ETest) GetMismatchedArch() string {
switch e2e.Arch {
case "arm64":
return "amd64"
default:
return"arm64"
}
}
28 changes: 21 additions & 7 deletions src/test/e2e/20_zarf_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
package test

import (
"context"
"fmt"
"testing"
"time"

"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
"github.com/stretchr/testify/require"
)

Expand All @@ -24,16 +22,32 @@ func TestZarfInit(t *testing.T) {
initComponents = "k3s,logging,git-server"
}

ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Minute)
defer cancel()
var (
mismatchedArch = e2e.GetMismatchedArch()
initPackageVersion = "UnknownVersion"
mismatchedInitPackage = fmt.Sprintf("zarf-init-%s-%s.tar.zst", mismatchedArch, initPackageVersion)
expectedErrorMessage = fmt.Sprintf("this package architecture is %s", mismatchedArch)
)

// Build init package with different arch than the cluster arch.
stdOut, stdErr, err := e2e.ExecZarfCommand("package", "create", ".", "--architecture", mismatchedArch, "--confirm")
require.NoError(t, err, stdOut, stdErr)
defer e2e.CleanFiles(mismatchedInitPackage)

// Check that `zarf init` fails in appliance mode when we try to initialize a k3s cluster
// on a machine with a different architecture than the package architecture.
// We need to use the --architecture flag here to force zarf to find the package.
_, stdErr, err = e2e.ExecZarfCommand("init", "--architecture", mismatchedArch, "--components=k3s", "--confirm")
require.Error(t, err, stdErr)
lucasrod16 marked this conversation as resolved.
Show resolved Hide resolved
require.Contains(t, stdErr, expectedErrorMessage)

// run `zarf init`
_, stdErr, err := exec.CmdWithContext(ctx, exec.PrintCfg(), e2e.ZarfBinPath, "init", "--components="+initComponents, "--confirm", "--nodeport", "31337")
_, stdErr, err = e2e.ExecZarfCommand("init", "--components="+initComponents, "--confirm", "--nodeport", "31337")
require.Contains(t, stdErr, "artifacts with software bill-of-materials (SBOM) included")
require.NoError(t, err)

// Check that gitea is actually running and healthy
stdOut, _, err := e2e.ExecZarfCommand("tools", "kubectl", "get", "pods", "-l", "app in (gitea)", "-n", "zarf", "-o", "jsonpath={.items[*].status.phase}")
stdOut, _, err = e2e.ExecZarfCommand("tools", "kubectl", "get", "pods", "-l", "app in (gitea)", "-n", "zarf", "-o", "jsonpath={.items[*].status.phase}")
require.NoError(t, err)
require.Contains(t, stdOut, "Running")

Expand Down
49 changes: 49 additions & 0 deletions src/test/e2e/29_mismatched_architectures_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors

// Package test provides e2e tests for Zarf.
package test

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

// TestMismatchedArchitectures ensures that zarf produces an error
// when the package architecture doesn't match the target cluster architecture.
func TestMismatchedArchitectures(t *testing.T) {
t.Log("E2E: Mismatched architectures")
e2e.SetupWithCluster(t)
defer e2e.Teardown(t)

var (
mismatchedArch = e2e.GetMismatchedArch()
mismatchedGamesPackage = fmt.Sprintf("zarf-package-dos-games-%s.tar.zst", mismatchedArch)
initPackageVersion = "UnknownVersion"
mismatchedInitPackage = fmt.Sprintf("zarf-init-%s-%s.tar.zst", mismatchedArch, initPackageVersion)
expectedErrorMessage = fmt.Sprintf("this package architecture is %s", mismatchedArch)
)

// Build init package with different arch than the cluster arch.
stdOut, stdErr, err := e2e.ExecZarfCommand("package", "create", ".", "--architecture", mismatchedArch, "--confirm")
require.NoError(t, err, stdOut, stdErr)
defer e2e.CleanFiles(mismatchedInitPackage)

// Build dos-games package with different arch than the cluster arch.
stdOut, stdErr, err = e2e.ExecZarfCommand("package", "create", "examples/dos-games/", "--architecture", mismatchedArch, "--confirm")
require.NoError(t, err, stdOut, stdErr)
defer e2e.CleanFiles(mismatchedGamesPackage)

// Ensure zarf init returns an error because of the mismatched architectures.
// We need to use the --architecture flag here to force zarf to find the package.
_, stdErr, err = e2e.ExecZarfCommand("init", "--architecture", mismatchedArch, "--confirm")
require.Error(t, err, stdErr)
require.Contains(t, stdErr, expectedErrorMessage)

// Ensure zarf package deploy returns an error because of the mismatched architectures.
_, stdErr, err = e2e.ExecZarfCommand("package", "deploy", mismatchedGamesPackage, "--confirm")
require.Error(t, err, stdErr)
require.Contains(t, stdErr, expectedErrorMessage)
}