Skip to content

Commit

Permalink
integration deb rpm (#4424)
Browse files Browse the repository at this point in the history
* add a DEB integration test

* fix package building of rpm and deb packages

* fix rebase conflicts

* add deb,rpm to serverless buildkite

* goimports -local
  • Loading branch information
leehinman authored Mar 19, 2024
1 parent 1d84d20 commit ddd832b
Show file tree
Hide file tree
Showing 19 changed files with 454 additions and 150 deletions.
2 changes: 1 addition & 1 deletion .buildkite/scripts/steps/integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ else
OVERRIDE_TEST_AGENT_VERSION=""
fi
# PACKAGE
AGENT_PACKAGE_VERSION="${OVERRIDE_AGENT_PACKAGE_VERSION}" DEV=true EXTERNAL=true SNAPSHOT=true PLATFORMS=linux/amd64,linux/arm64,windows/amd64 PACKAGES=tar.gz,zip mage package
AGENT_PACKAGE_VERSION="${OVERRIDE_AGENT_PACKAGE_VERSION}" DEV=true EXTERNAL=true SNAPSHOT=true PLATFORMS=linux/amd64,linux/arm64,windows/amd64 PACKAGES=tar.gz,zip,rpm,deb mage package

# Run integration tests
set +e
Expand Down
9 changes: 6 additions & 3 deletions dev-tools/mage/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func Package() error {
// platforms := updateWithDarwinUniversal(Platforms)
platforms := Platforms

var tasks []interface{}
tasks := make(map[string][]interface{})
for _, target := range platforms {
for _, pkg := range Packages {
if pkg.OS != target.GOOS() || pkg.Arch != "" && pkg.Arch != target.Arch() {
Expand Down Expand Up @@ -94,12 +94,15 @@ func Package() error {

spec = spec.Evaluate()

tasks = append(tasks, packageBuilder{target, spec, pkgType}.Build)
tasks[target.GOOS()+"-"+target.Arch()] = append(tasks[target.GOOS()+"-"+target.Arch()], packageBuilder{target, spec, pkgType}.Build)
}
}
}

Parallel(tasks...)
for k, v := range tasks {
fmt.Printf(">> package: Building %s\n", k)
Parallel(v...)
}
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/testing/define/define.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func runOrSkip(t *testing.T, req Requirements, local bool) *Info {
panic("failed to get OS information")
}
if !req.runtimeAllowed(runtime.GOOS, runtime.GOARCH, osInfo.Version, osInfo.Platform) {
t.Skip("platform, architecture, version, and distro not supported by test")
t.Skipf("platform: %s, architecture: %s, version: %s, and distro: %s combination is not supported by test. required: %v", runtime.GOOS, runtime.GOARCH, osInfo.Version, osInfo.Platform, req.OS)
return nil
}
namespace, err := getNamespace(t, local)
Expand Down
39 changes: 39 additions & 0 deletions pkg/testing/fetch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package testing

import (
"errors"
gtesting "testing"
)

func TestGetPackageSuffix(t *gtesting.T) {
tests := map[string]struct {
os string
arch string
format string
expected string
err error
}{
"windows zip": {os: "windows", arch: "amd64", format: "zip", expected: "windows-x86_64.zip", err: nil},
"windows msi": {os: "windows", arch: "amd64", format: "msi", expected: "", err: ErrUnsupportedPlatform},
"linux deb": {os: "linux", arch: "amd64", format: "deb", expected: "amd64.deb", err: nil},
"linux rpm": {os: "linux", arch: "amd64", format: "rpm", expected: "x86_64.rpm", err: nil},
"linux tar.gz": {os: "linux", arch: "amd64", format: "targz", expected: "linux-x86_64.tar.gz", err: nil},
"linux pkg.tar.zst": {os: "linux", arch: "amd64", format: "pkg.tar.zst", expected: "", err: ErrUnsupportedPlatform},
"darwin arm64": {os: "darwin", arch: "arm64", format: "targz", expected: "darwin-aarch64.tar.gz", err: nil},
}
for name, tc := range tests {
t.Run(name, func(t *gtesting.T) {
got, err := GetPackageSuffix(tc.os, tc.arch, tc.format)
if !errors.Is(err, tc.err) {
t.Fatalf("wrong error. expected: %v got: %v", tc.err, err)
}
if got != tc.expected {
t.Fatalf("wrong output. expected: %s got: %s", tc.expected, got)
}
})
}
}
28 changes: 19 additions & 9 deletions pkg/testing/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,23 @@ var (
// packageArchMap provides a mapping for the endings of the builds of Elastic Agent based on the
// operating system and architecture.
var packageArchMap = map[string]string{
"linux-amd64": "linux-x86_64.tar.gz",
"linux-arm64": "linux-arm64.tar.gz",
"windows-amd64": "windows-x86_64.zip",
"darwin-amd64": "darwin-x86_64.tar.gz",
"darwin-arm64": "darwin-aarch64.tar.gz",
"linux-amd64-targz": "linux-x86_64.tar.gz",
"linux-amd64-deb": "amd64.deb",
"linux-amd64-rpm": "x86_64.rpm",
"linux-arm64-targz": "linux-arm64.tar.gz",
"linux-arm64-deb": "arm64.deb",
"linux-arm64-rpm": "aarch64.rpm",
"windows-amd64-zip": "windows-x86_64.zip",
"darwin-amd64-targz": "darwin-x86_64.tar.gz",
"darwin-arm64-targz": "darwin-aarch64.tar.gz",
}

// GetPackageSuffix returns the suffix ending for the builds of Elastic Agent based on the
// operating system and architecture.
func GetPackageSuffix(operatingSystem string, architecture string) (string, error) {
suffix, ok := packageArchMap[fmt.Sprintf("%s-%s", operatingSystem, architecture)]
func GetPackageSuffix(operatingSystem string, architecture string, packageFormat string) (string, error) {
suffix, ok := packageArchMap[fmt.Sprintf("%s-%s-%s", operatingSystem, architecture, packageFormat)]
if !ok {
return "", fmt.Errorf("%w: %s/%s", ErrUnsupportedPlatform, operatingSystem, architecture)
return "", fmt.Errorf("%w: %s/%s/%s", ErrUnsupportedPlatform, operatingSystem, architecture, packageFormat)
}
return suffix, nil
}
Expand All @@ -68,7 +72,7 @@ type Fetcher interface {
//
// The extraction is handled by the caller. This should only download the file
// and place it into the directory.
Fetch(ctx context.Context, operatingSystem string, architecture string, version string) (FetcherResult, error)
Fetch(ctx context.Context, operatingSystem string, architecture string, version string, packageFormat string) (FetcherResult, error)
}

// fetchCache is global to all tests, reducing the time required to fetch the needed artifacts
Expand Down Expand Up @@ -105,6 +109,12 @@ func splitFileType(name string) (string, string, error) {
if strings.HasSuffix(name, ".zip") {
return strings.TrimSuffix(name, ".zip"), ".zip", nil
}
if strings.HasSuffix(name, ".deb") {
return strings.TrimSuffix(name, ".deb"), ".deb", nil
}
if strings.HasSuffix(name, ".rpm") {
return strings.TrimSuffix(name, ".rpm"), ".rpm", nil
}
return "", "", fmt.Errorf("unknown file extension type: %s", filepath.Ext(name))
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/testing/fetcher_artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ func (f *artifactFetcher) Name() string {
}

// Fetch fetches the Elastic Agent and places the resulting binary at the path.
func (f *artifactFetcher) Fetch(ctx context.Context, operatingSystem string, architecture string, version string) (FetcherResult, error) {
suffix, err := GetPackageSuffix(operatingSystem, architecture)
func (f *artifactFetcher) Fetch(ctx context.Context, operatingSystem string, architecture string, version string, packageFormat string) (FetcherResult, error) {
suffix, err := GetPackageSuffix(operatingSystem, architecture, packageFormat)
if err != nil {
return nil, err
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/testing/fetcher_artifact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestArtifactFetcher_Default(t *testing.T) {
af.doer = newFakeHttpClient(t)

tmp := t.TempDir()
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.12.0")
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.12.0", "targz")
require.NoError(t, err)

err = res.Fetch(context.Background(), t, tmp)
Expand All @@ -46,7 +46,7 @@ func TestArtifactFetcher_Snapshot(t *testing.T) {
af.doer = newFakeHttpClient(t)

tmp := t.TempDir()
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.13.0-SNAPSHOT")
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.13.0-SNAPSHOT", "targz")
require.NoError(t, err)

err = res.Fetch(context.Background(), t, tmp)
Expand All @@ -64,7 +64,7 @@ func TestArtifactFetcher_SnapshotOnly(t *testing.T) {
af.doer = newFakeHttpClient(t)

tmp := t.TempDir()
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.13.0")
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.13.0", "targz")
require.NoError(t, err)

err = res.Fetch(context.Background(), t, tmp)
Expand All @@ -82,7 +82,7 @@ func TestArtifactFetcher_Build(t *testing.T) {
af.doer = newFakeHttpClient(t)

tmp := t.TempDir()
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.13.0-SNAPSHOT+l5snflwr")
res, err := f.Fetch(context.Background(), "linux", "amd64", "8.13.0-SNAPSHOT+l5snflwr", "targz")
require.NoError(t, err)

err = res.Fetch(context.Background(), t, tmp)
Expand Down
4 changes: 2 additions & 2 deletions pkg/testing/fetcher_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ func (h HttpFetcher) Name() string {
return fmt.Sprintf("httpFetcher-%s", sanitizeFetcherName(h.baseURL))
}

func (h HttpFetcher) Fetch(ctx context.Context, operatingSystem string, architecture string, version string) (FetcherResult, error) {
suffix, err := GetPackageSuffix(operatingSystem, architecture)
func (h HttpFetcher) Fetch(ctx context.Context, operatingSystem string, architecture string, version string, packageFormat string) (FetcherResult, error) {
suffix, err := GetPackageSuffix(operatingSystem, architecture, packageFormat)
if err != nil {
return nil, err
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/testing/fetcher_http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestHttpFetcher_Fetch(t *testing.T) {
operatingSystem string
architecture string
version string
pkgFormat string
}
tests := []struct {
name string
Expand All @@ -38,6 +39,7 @@ func TestHttpFetcher_Fetch(t *testing.T) {
operatingSystem: "linux",
architecture: "arm64",
version: "1.2.3",
pkgFormat: "targz",
},
want: &httpFetcherResult{
baseURL: "https://artifacts.elastic.co/downloads/beats/elastic-agent/",
Expand All @@ -52,6 +54,7 @@ func TestHttpFetcher_Fetch(t *testing.T) {
operatingSystem: "windows",
architecture: "amd64",
version: "1.2.3",
pkgFormat: "zip",
},
want: &httpFetcherResult{
baseURL: "http://somehost.somedomain/some/path/here",
Expand All @@ -69,7 +72,7 @@ func TestHttpFetcher_Fetch(t *testing.T) {
h := NewHttpFetcher(opts...)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
got, err := h.Fetch(ctx, tt.args.operatingSystem, tt.args.architecture, tt.args.version)
got, err := h.Fetch(ctx, tt.args.operatingSystem, tt.args.architecture, tt.args.version, tt.args.pkgFormat)
if !tt.wantErr(t, err, fmt.Sprintf("Fetch(%v, %v, %v, %v)", ctx, tt.args.operatingSystem, tt.args.architecture, tt.args.version)) {
return
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/testing/fetcher_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ func (f *localFetcher) Name() string {
}

// Fetch fetches the Elastic Agent and places the resulting binary at the path.
func (f *localFetcher) Fetch(_ context.Context, operatingSystem string, architecture string, version string) (FetcherResult, error) {
suffix, err := GetPackageSuffix(operatingSystem, architecture)
func (f *localFetcher) Fetch(_ context.Context, operatingSystem string, architecture string, version string, packageFormat string) (FetcherResult, error) {
suffix, err := GetPackageSuffix(operatingSystem, architecture, packageFormat)
if err != nil {
return nil, err
}
Expand Down
12 changes: 10 additions & 2 deletions pkg/testing/fetcher_local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ func TestLocalFetcher(t *testing.T) {
snapshotContentHash := []byte("snapshot contents hash")
noSnapshotContent := []byte("not snapshot contents")
noSnapshotContentHash := []byte("not snapshot contents hash")
pkgFormat := "targz"
if runtime.GOOS == "windows" {
pkgFormat = "zip"
}

testdata := t.TempDir()
suffix, err := GetPackageSuffix(runtime.GOOS, runtime.GOARCH)
suffix, err := GetPackageSuffix(runtime.GOOS, runtime.GOARCH, pkgFormat)
require.NoError(t, err)

snapshotPath := fmt.Sprintf("elastic-agent-%s-SNAPSHOT-%s", baseVersion, suffix)
Expand Down Expand Up @@ -92,8 +96,12 @@ func TestLocalFetcher(t *testing.T) {
tmp := t.TempDir()

f := LocalFetcher(testdata, tc.opts...)
pkgFormat := "targz"
if runtime.GOOS == "windows" {
pkgFormat = "zip"
}
got, err := f.Fetch(
context.Background(), runtime.GOOS, runtime.GOARCH, tc.version)
context.Background(), runtime.GOOS, runtime.GOARCH, tc.version, pkgFormat)
require.NoError(t, err)

err = got.Fetch(context.Background(), t, tmp)
Expand Down
29 changes: 28 additions & 1 deletion pkg/testing/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Fixture struct {
fetcher Fetcher
operatingSystem string
architecture string
packageFormat string
logOutput bool
allowErrs bool
connectTimout time.Duration
Expand Down Expand Up @@ -83,6 +84,14 @@ func WithOSArchitecture(operatingSystem string, architecture string) FixtureOpt
}
}

// WithPackageFormat changes the package format to use for the fixture.
// By default, targz is picked except for windows which uses zip
func WithPackageFormat(packageFormat string) FixtureOpt {
return func(f *Fixture) {
f.packageFormat = packageFormat
}
}

// WithLogOutput instructs the fixture to log all Elastic Agent output to the test log.
// By default, the Elastic Agent output will not be logged to the test logger.
func WithLogOutput() FixtureOpt {
Expand Down Expand Up @@ -139,13 +148,18 @@ func NewFixture(t *testing.T, version string, opts ...FixtureOpt) (*Fixture, err
if !ok {
return nil, errors.New("unable to determine callers file path")
}
pkgFormat := "targz"
if runtime.GOOS == "windows" {
pkgFormat = "zip"
}
f := &Fixture{
t: t,
version: version,
caller: caller,
fetcher: ArtifactFetcher(),
operatingSystem: runtime.GOOS,
architecture: runtime.GOARCH,
packageFormat: pkgFormat,
connectTimout: 15 * time.Second,
// default to elastic-agent, can be changed by a set FixtureOpt below
binaryName: "elastic-agent",
Expand Down Expand Up @@ -253,6 +267,11 @@ func (f *Fixture) SrcPackage(ctx context.Context) (string, error) {
return f.srcPackage, nil
}

// PackageFormat returns the package format for the fixture
func (f *Fixture) PackageFormat() string {
return f.packageFormat
}

func ExtractArtifact(l Logger, artifactFile, outputDir string) error {
filename := filepath.Base(artifactFile)
_, ext, err := splitFileType(filename)
Expand All @@ -271,6 +290,11 @@ func ExtractArtifact(l Logger, artifactFile, outputDir string) error {
if err != nil {
return fmt.Errorf("failed to unzip %s: %w", artifactFile, err)
}
case ".deb", "rpm":
err := copy.Copy(artifactFile, filepath.Join(outputDir, filepath.Base(artifactFile)))
if err != nil {
return fmt.Errorf("failed to copy %s to %s: %w", artifactFile, outputDir, err)
}
}
l.Logf("Completed extraction of artifact %s to %s", filename, outputDir)
return nil
Expand Down Expand Up @@ -813,6 +837,9 @@ func (f *Fixture) binaryPath() string {
workDir = filepath.Join(paths.DefaultBasePath, "Elastic", "Agent")
}
}
if f.packageFormat == "deb" {
workDir = "/usr/bin"
}
defaultBin := "elastic-agent"
if f.binaryName != "" {
defaultBin = f.binaryName
Expand Down Expand Up @@ -840,7 +867,7 @@ func (f *Fixture) fetch(ctx context.Context) (string, error) {
cache.dir = dir
}

res, err := f.fetcher.Fetch(ctx, f.operatingSystem, f.architecture, f.version)
res, err := f.fetcher.Fetch(ctx, f.operatingSystem, f.architecture, f.version, f.packageFormat)
if err != nil {
return "", err
}
Expand Down
Loading

0 comments on commit ddd832b

Please sign in to comment.