omni/internal/integration/cli_test.go
Artem Chernyshev 122b79605f
Some checks are pending
default / default (push) Waiting to run
default / e2e-backups (push) Blocked by required conditions
default / e2e-forced-removal (push) Blocked by required conditions
default / e2e-scaling (push) Blocked by required conditions
default / e2e-short (push) Blocked by required conditions
default / e2e-short-secureboot (push) Blocked by required conditions
default / e2e-templates (push) Blocked by required conditions
default / e2e-upgrades (push) Blocked by required conditions
default / e2e-workload-proxy (push) Blocked by required conditions
test: run Omni as part of integration tests
This enables test coverage, builds Omni with race detector.

Also redone the COSI state creation flow: no more callbacks.
The state is now an Object, which has `Stop` method, that should be
called when the app stops.
All defers were moved into the `Stop` method basically.

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
2025-06-18 16:20:11 +03:00

174 lines
4.9 KiB
Go

// Copyright (c) 2025 Sidero Labs, Inc.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//go:build integration
package integration_test
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/google/uuid"
"github.com/siderolabs/go-api-signature/pkg/pgp"
"github.com/siderolabs/go-api-signature/pkg/serviceaccount"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/stretchr/testify/require"
pkgaccess "github.com/siderolabs/omni/client/pkg/access"
"github.com/siderolabs/omni/client/pkg/client"
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
"github.com/siderolabs/omni/internal/pkg/auth"
"github.com/siderolabs/omni/internal/pkg/auth/role"
)
// AssertDownloadUsingCLI verifies generated image download using omnictl.
func AssertDownloadUsingCLI(testCtx context.Context, client *client.Client, omnictlPath, httpEndpoint string) TestFunc {
st := client.Omni().State()
return func(t *testing.T) {
t.Parallel()
if omnictlPath == "" {
t.Skip()
}
media, err := safe.StateListAll[*omni.InstallationMedia](testCtx, st)
require.NoError(t, err)
var images []*omni.InstallationMedia
for val := range media.All() {
spec := val.TypedSpec().Value
switch spec.Profile {
case constants.BoardRPiGeneric:
fallthrough
case "aws":
fallthrough
case "iso":
images = append(images, val)
}
}
require.Greater(t, len(images), 2)
name := "test-" + uuid.NewString()
key := createServiceAccount(testCtx, t, client, name, role.Admin)
for _, image := range images {
t.Run(image.Metadata().ID(), func(t *testing.T) {
t.Parallel()
output := filepath.Join(t.TempDir(), image.Metadata().ID())
stdout, stderr, err := runCmd(
omnictlPath,
httpEndpoint,
key, "download",
"--insecure-skip-tls-verify",
image.TypedSpec().Value.Name,
"--initial-labels",
"key=value",
"--output",
output)
require.NoError(t, err, "stdout:\n %s\nstderr:\n%s", stdout.String(), stderr.String())
res, err := os.Stat(output)
require.NoError(t, err)
require.Greater(t, res.Size(), int64(1024*1024))
})
}
}
}
func runCmd(path, endpoint, key string, args ...string) (bytes.Buffer, bytes.Buffer, error) {
var stdout, stderr bytes.Buffer
args = append([]string{"--insecure-skip-tls-verify"}, args...)
cmd := exec.Command(
path,
args...,
)
cmd.Stdin = nil
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Env = []string{
fmt.Sprintf("OMNI_ENDPOINT=%s", endpoint),
fmt.Sprintf("OMNI_SERVICE_ACCOUNT_KEY=%s", key),
}
if err := cmd.Start(); err != nil {
return stdout, stderr, err
}
err := cmd.Wait()
return stdout, stderr, err
}
func createServiceAccount(ctx context.Context, t *testing.T, client *client.Client, name string, role role.Role) string {
// generate a new PGP key with long lifetime
comment := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
serviceAccountEmail := name + pkgaccess.ServiceAccountNameSuffix
key, err := pgp.GenerateKey(name, comment, serviceAccountEmail, auth.ServiceAccountMaxAllowedLifetime)
require.NoError(t, err)
armoredPublicKey, err := key.ArmorPublic()
require.NoError(t, err)
// create service account with the generated key
_, err = client.Management().CreateServiceAccount(ctx, name, armoredPublicKey, string(role), false)
require.NoError(t, err)
encodedKey, err := serviceaccount.Encode(name, key)
require.NoError(t, err)
return encodedKey
}
// AssertUserCLI verifies user management cli commands.
func AssertUserCLI(testCtx context.Context, client *client.Client, omnictlPath, httpEndpoint string) TestFunc {
return func(t *testing.T) {
name := "test-" + uuid.NewString()
key := createServiceAccount(testCtx, t, client, name, role.Admin)
stdout, stderr, err := runCmd(omnictlPath, httpEndpoint, key, "user", "create", "a@a.com", "--role", "Admin")
require.NoErrorf(t, err, "failed to create user. stdout: %q | stderr: %q", stdout.String(), stderr.String())
stdout, stderr, err = runCmd(omnictlPath, httpEndpoint, key, "user", "list")
require.NoErrorf(t, err, "failed to list users. stdout: %q | stderr: %q", stdout.String(), stderr.String())
require.Contains(t, stdout.String(), "a@a.com")
stdout, stderr, err = runCmd(omnictlPath, httpEndpoint, key, "user", "set-role", "--role", "Reader", "a@a.com")
require.NoErrorf(t, err, "failed to set role. stdout: %q | stderr: %q", stdout.String(), stderr.String())
stdout, stderr, err = runCmd(omnictlPath, httpEndpoint, key, "user", "delete", "a@a.com")
require.NoErrorf(t, err, "failed to delete user. stdout: %q | stderr: %q", stdout.String(), stderr.String())
stdout, stderr, err = runCmd(omnictlPath, httpEndpoint, key, "user", "list")
require.NoErrorf(t, err, "failed to list users. stdout: %q | stderr: %q", stdout.String(), stderr.String())
require.NotContains(t, stdout.String(), "a@a.com")
}
}