The original Koji implementation expected that the output of a content generator is only an image. While in reality, we will eventually upload other types of files as outputs to Koji, such as logs and osbuild manifest. Rename Koji structures and their members to better map to the upstream Koji documentation and their JSON representation. Add comments to structures. Define type aliases and constants for string values which are more like enums, than a free-form values. These changes have no effect on the actual JSON representation of any of the structures Signed-off-by: Tomáš Hozza <thozza@redhat.com>
219 lines
5.6 KiB
Go
219 lines
5.6 KiB
Go
// This command contains some tests for the koji integration. It's a bit
|
|
// different from the other cmd/*-tests executables because it cannot be
|
|
// currently run as a "base test". Instead, it's run as a part of the
|
|
// koji.sh test because it needs a working Koji instance to pass.
|
|
|
|
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/osbuild/images/pkg/rpmmd"
|
|
"github.com/osbuild/osbuild-composer/internal/upload/koji"
|
|
)
|
|
|
|
func TestKojiRefund(t *testing.T) {
|
|
shareDir := "/tmp/osbuild-composer-koji-test"
|
|
server := "https://localhost:4343/kojihub"
|
|
|
|
// base our transport on the default one
|
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
|
|
|
// use the self-signed certificate generated by run-koji-container
|
|
certPool := x509.NewCertPool()
|
|
cert, err := os.ReadFile(shareDir + "/ca-crt.pem")
|
|
require.NoError(t, err)
|
|
|
|
ok := certPool.AppendCertsFromPEM(cert)
|
|
require.True(t, ok)
|
|
|
|
transport.TLSClientConfig = &tls.Config{
|
|
RootCAs: certPool,
|
|
MinVersion: tls.VersionTLS12,
|
|
}
|
|
|
|
// login
|
|
credentials := &koji.GSSAPICredentials{
|
|
Principal: "osbuild-krb@LOCAL",
|
|
KeyTab: shareDir + "/client.keytab",
|
|
}
|
|
k, err := koji.NewFromGSSAPI(server, credentials, transport)
|
|
require.NoError(t, err)
|
|
|
|
defer func() {
|
|
err := k.Logout()
|
|
if err != nil {
|
|
require.NoError(t, err)
|
|
}
|
|
}()
|
|
|
|
initResult, err := k.CGInitBuild("name", "verison", "release")
|
|
require.NoError(t, err)
|
|
|
|
err = k.CGCancelBuild(initResult.BuildID, initResult.Token)
|
|
require.NoError(t, err)
|
|
|
|
err = k.CGCancelBuild(initResult.BuildID, initResult.Token)
|
|
require.Error(t, err)
|
|
|
|
initResult, err = k.CGInitBuild("name", "verison", "release")
|
|
require.NoError(t, err)
|
|
|
|
err = k.CGFailBuild(initResult.BuildID, initResult.Token)
|
|
require.NoError(t, err)
|
|
|
|
err = k.CGFailBuild(initResult.BuildID, initResult.Token)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestKojiImport(t *testing.T) {
|
|
// define constants
|
|
server := "https://localhost:4343/kojihub"
|
|
filename := "image.qcow2"
|
|
filesize := 1024
|
|
shareDir := "/tmp/osbuild-composer-koji-test"
|
|
// you cannot create two build with a same name, let's create a random one each time
|
|
buildName := "osbuild-image-" + uuid.Must(uuid.NewRandom()).String()
|
|
// koji needs to specify a directory to which the upload should happen, let's reuse the build name
|
|
uploadDirectory := buildName
|
|
|
|
// base our transport on the default one
|
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
|
|
|
// use the self-signed certificate generated by run-koji-container
|
|
certPool := x509.NewCertPool()
|
|
cert, err := os.ReadFile(shareDir + "/ca-crt.pem")
|
|
require.NoError(t, err)
|
|
|
|
ok := certPool.AppendCertsFromPEM(cert)
|
|
require.True(t, ok)
|
|
|
|
transport.TLSClientConfig = &tls.Config{
|
|
RootCAs: certPool,
|
|
MinVersion: tls.VersionTLS12,
|
|
}
|
|
|
|
// login
|
|
credentials := &koji.GSSAPICredentials{
|
|
Principal: "osbuild-krb@LOCAL",
|
|
KeyTab: shareDir + "/client.keytab",
|
|
}
|
|
k, err := koji.NewFromGSSAPI(server, credentials, transport)
|
|
require.NoError(t, err)
|
|
|
|
defer func() {
|
|
err := k.Logout()
|
|
if err != nil {
|
|
require.NoError(t, err)
|
|
}
|
|
}()
|
|
|
|
// Create a random file
|
|
f, err := os.CreateTemp("", "osbuild-koji-test-*.qcow2")
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
assert.NoError(t, f.Close())
|
|
assert.NoError(t, os.Remove(f.Name()))
|
|
}()
|
|
|
|
_, err = io.CopyN(f, rand.Reader, int64(filesize))
|
|
require.NoError(t, err)
|
|
_, err = f.Seek(0, io.SeekStart)
|
|
require.NoError(t, err)
|
|
|
|
// Upload the file
|
|
hash, _, err := k.Upload(f, uploadDirectory, filename)
|
|
require.NoError(t, err)
|
|
|
|
// Import the build
|
|
build := koji.Build{
|
|
TaskID: 1,
|
|
Name: buildName,
|
|
Version: "1",
|
|
Release: "1",
|
|
StartTime: time.Now().Unix(),
|
|
EndTime: time.Now().Unix(),
|
|
}
|
|
buildRoots := []koji.BuildRoot{
|
|
{
|
|
ID: 1,
|
|
Host: koji.Host{
|
|
Os: "RHEL8",
|
|
Arch: "noarch",
|
|
},
|
|
ContentGenerator: koji.ContentGenerator{
|
|
Name: "osbuild",
|
|
Version: "1",
|
|
},
|
|
Container: koji.Container{
|
|
Type: "nspawn",
|
|
Arch: "noarch",
|
|
},
|
|
Tools: []koji.Tool{},
|
|
RPMs: []rpmmd.RPM{},
|
|
},
|
|
}
|
|
output := []koji.BuildOutput{
|
|
{
|
|
BuildRootID: 1,
|
|
Filename: filename,
|
|
FileSize: uint64(filesize),
|
|
Arch: "noarch",
|
|
ChecksumType: koji.ChecksumTypeMD5,
|
|
Checksum: hash,
|
|
Type: koji.BuildOutputTypeImage,
|
|
RPMs: []rpmmd.RPM{},
|
|
Extra: koji.BuildOutputExtra{
|
|
Image: koji.ImageExtraInfo{
|
|
Arch: "noarch",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
initResult, err := k.CGInitBuild(build.Name, build.Version, build.Release)
|
|
require.NoError(t, err)
|
|
|
|
build.BuildID = uint64(initResult.BuildID)
|
|
|
|
importResult, err := k.CGImport(build, buildRoots, output, uploadDirectory, initResult.Token)
|
|
require.NoError(t, err)
|
|
|
|
// check if the build is really there:
|
|
// There's no potential command injection vector here
|
|
/* #nosec G204 */
|
|
cmd := exec.Command(
|
|
"koji",
|
|
"--server", server,
|
|
"-c", "/usr/share/tests/osbuild-composer/koji/koji.conf",
|
|
"--keytab", credentials.KeyTab,
|
|
"--principal", credentials.Principal,
|
|
"list-builds",
|
|
"--buildid", strconv.Itoa(importResult.BuildID),
|
|
)
|
|
|
|
// sample output:
|
|
// Build Built by State
|
|
// ------------------------------------------------------- ---------------- ----------------
|
|
// osbuild-image-92882b90-4bd9-4422-8b8a-40863f94535a-1-1 osbuild COMPLETE
|
|
out, err := cmd.CombinedOutput()
|
|
assert.NoError(t, err)
|
|
|
|
// let's check for COMPLETE, koji will exit with non-zero status code if the build doesn't exist
|
|
assert.Contains(t, string(out), "COMPLETE")
|
|
}
|