mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-02-04 09:05:31 -05:00
cli: image info (v2)
This commit is contained in:
parent
cd7b116794
commit
d0e53cbb59
@ -17,7 +17,6 @@ go_library(
|
||||
deps = [
|
||||
"//cli/internal/clusterid",
|
||||
"//cli/internal/iamid",
|
||||
"//cli/internal/image",
|
||||
"//cli/internal/libvirt",
|
||||
"//cli/internal/terraform",
|
||||
"//internal/atls",
|
||||
@ -27,6 +26,7 @@ go_library(
|
||||
"//internal/cloud/gcpshared",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/imagefetcher",
|
||||
"//internal/variant",
|
||||
"@com_github_azure_azure_sdk_for_go//profiles/latest/attestation/attestation",
|
||||
"@com_github_azure_azure_sdk_for_go_sdk_azcore//policy",
|
||||
@ -54,6 +54,7 @@ go_test(
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/cloud/gcpshared",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"@com_github_hashicorp_terraform_json//:terraform-json",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
|
@ -12,13 +12,16 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tfjson "github.com/hashicorp/terraform-json"
|
||||
)
|
||||
|
||||
// imageFetcher gets an image reference from the versionsapi.
|
||||
type imageFetcher interface {
|
||||
FetchReference(ctx context.Context, config *config.Config) (string, error)
|
||||
FetchReference(ctx context.Context,
|
||||
provider cloudprovider.Provider, attestationVariant variant.Variant,
|
||||
image, region string,
|
||||
) (string, error)
|
||||
}
|
||||
|
||||
type terraformClient interface {
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tfjson "github.com/hashicorp/terraform-json"
|
||||
|
||||
"go.uber.org/goleak"
|
||||
@ -103,7 +103,10 @@ type stubImageFetcher struct {
|
||||
fetchReferenceErr error
|
||||
}
|
||||
|
||||
func (f *stubImageFetcher) FetchReference(_ context.Context, _ *config.Config) (string, error) {
|
||||
func (f *stubImageFetcher) FetchReference(_ context.Context,
|
||||
_ cloudprovider.Provider, _ variant.Variant,
|
||||
_, _ string,
|
||||
) (string, error) {
|
||||
return f.reference, f.fetchReferenceErr
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,12 @@ import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/image"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
)
|
||||
|
||||
@ -48,7 +48,7 @@ type Creator struct {
|
||||
func NewCreator(out io.Writer) *Creator {
|
||||
return &Creator{
|
||||
out: out,
|
||||
image: image.New(),
|
||||
image: imagefetcher.New(),
|
||||
newTerraformClient: func(ctx context.Context) (terraformClient, error) {
|
||||
return terraform.New(ctx, constants.TerraformWorkingDir)
|
||||
},
|
||||
@ -56,7 +56,7 @@ func NewCreator(out io.Writer) *Creator {
|
||||
return libvirt.New()
|
||||
},
|
||||
newRawDownloader: func() rawDownloader {
|
||||
return image.NewDownloader()
|
||||
return imagefetcher.NewDownloader()
|
||||
},
|
||||
policyPatcher: policyPatcher{},
|
||||
}
|
||||
@ -75,7 +75,10 @@ type CreateOptions struct {
|
||||
|
||||
// Create creates the handed amount of instances and all the needed resources.
|
||||
func (c *Creator) Create(ctx context.Context, opts CreateOptions) (clusterid.File, error) {
|
||||
image, err := c.image.FetchReference(ctx, opts.Config)
|
||||
provider := opts.Config.GetProvider()
|
||||
attestationVariant := opts.Config.GetAttestationConfig().GetVariant()
|
||||
region := opts.Config.GetRegion()
|
||||
image, err := c.image.FetchReference(ctx, provider, attestationVariant, opts.Config.Image, region)
|
||||
if err != nil {
|
||||
return clusterid.File{}, fmt.Errorf("fetching image reference: %w", err)
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ go_library(
|
||||
"//cli/internal/clusterid",
|
||||
"//cli/internal/helm",
|
||||
"//cli/internal/iamid",
|
||||
"//cli/internal/image",
|
||||
"//cli/internal/kubernetes",
|
||||
"//cli/internal/libvirt",
|
||||
"//cli/internal/terraform",
|
||||
@ -62,6 +61,7 @@ go_library(
|
||||
"//internal/file",
|
||||
"//internal/grpc/dialer",
|
||||
"//internal/grpc/retry",
|
||||
"//internal/imagefetcher",
|
||||
"//internal/kms/uri",
|
||||
"//internal/kubernetes/kubectl",
|
||||
"//internal/license",
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/image"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
||||
@ -25,6 +24,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
@ -65,7 +65,7 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fetcher := image.New()
|
||||
fetcher := imagefetcher.New()
|
||||
|
||||
applyCmd := upgradeApplyCmd{upgrader: upgrader, log: log, fetcher: fetcher}
|
||||
return applyCmd.upgradeApply(cmd, fileHandler)
|
||||
@ -194,7 +194,10 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, file file.Handler
|
||||
|
||||
func (u *upgradeApplyCmd) parseUpgradeVars(cmd *cobra.Command, conf *config.Config, fetcher imageFetcher) ([]string, terraform.Variables, error) {
|
||||
// Fetch variables to execute Terraform script with
|
||||
imageRef, err := fetcher.FetchReference(cmd.Context(), conf)
|
||||
provider := conf.GetProvider()
|
||||
attestationVariant := conf.GetAttestationConfig().GetVariant()
|
||||
region := conf.GetRegion()
|
||||
imageRef, err := fetcher.FetchReference(cmd.Context(), provider, attestationVariant, conf.Image, region)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("fetching image reference: %w", err)
|
||||
}
|
||||
@ -264,7 +267,10 @@ func (u *upgradeApplyCmd) parseUpgradeVars(cmd *cobra.Command, conf *config.Conf
|
||||
}
|
||||
|
||||
type imageFetcher interface {
|
||||
FetchReference(ctx context.Context, conf *config.Config) (string, error)
|
||||
FetchReference(ctx context.Context,
|
||||
provider cloudprovider.Provider, attestationVariant variant.Variant,
|
||||
image, region string,
|
||||
) (string, error)
|
||||
}
|
||||
|
||||
// upgradeAttestConfigIfDiff checks if the locally configured measurements are different from the cluster's measurements.
|
||||
|
@ -200,6 +200,9 @@ type stubImageFetcher struct {
|
||||
fetchReferenceErr error
|
||||
}
|
||||
|
||||
func (s stubImageFetcher) FetchReference(context.Context, *config.Config) (string, error) {
|
||||
return "", s.fetchReferenceErr
|
||||
func (f stubImageFetcher) FetchReference(_ context.Context,
|
||||
_ cloudprovider.Provider, _ variant.Variant,
|
||||
_, _ string,
|
||||
) (string, error) {
|
||||
return "", f.fetchReferenceErr
|
||||
}
|
||||
|
@ -12,14 +12,15 @@ go_library(
|
||||
visibility = ["//cli:__subpackages__"],
|
||||
deps = [
|
||||
"//cli/internal/helm",
|
||||
"//cli/internal/image",
|
||||
"//cli/internal/terraform",
|
||||
"//cli/internal/upgrade",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/compatibility",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/file",
|
||||
"//internal/imagefetcher",
|
||||
"//internal/kubernetes",
|
||||
"//internal/kubernetes/kubectl",
|
||||
"//internal/variant",
|
||||
@ -45,10 +46,12 @@ go_test(
|
||||
embed = [":kubernetes"],
|
||||
deps = [
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/compatibility",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/logger",
|
||||
"//internal/variant",
|
||||
"//internal/versions",
|
||||
"//internal/versions/components",
|
||||
"//operators/constellation-node-operator/api/v1alpha1",
|
||||
|
@ -16,14 +16,15 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/image"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||
internalk8s "github.com/edgelesssys/constellation/v2/internal/kubernetes"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
@ -122,7 +123,7 @@ func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog) (*Upgra
|
||||
stableInterface: &stableClient{client: kubeClient},
|
||||
dynamicInterface: &NodeVersionClient{client: unstructuredClient},
|
||||
helmClient: helmClient,
|
||||
imageFetcher: image.New(),
|
||||
imageFetcher: imagefetcher.New(),
|
||||
outWriter: outWriter,
|
||||
tfUpgrader: tfUpgrader,
|
||||
log: log,
|
||||
@ -164,7 +165,10 @@ func (u *Upgrader) UpgradeHelmServices(ctx context.Context, config *config.Confi
|
||||
// UpgradeNodeVersion upgrades the cluster's NodeVersion object and in turn triggers image & k8s version upgrades.
|
||||
// The versions set in the config are validated against the versions running in the cluster.
|
||||
func (u *Upgrader) UpgradeNodeVersion(ctx context.Context, conf *config.Config) error {
|
||||
imageReference, err := u.imageFetcher.FetchReference(ctx, conf)
|
||||
provider := conf.GetProvider()
|
||||
attestationVariant := conf.GetAttestationConfig().GetVariant()
|
||||
region := conf.GetRegion()
|
||||
imageReference, err := u.imageFetcher.FetchReference(ctx, provider, attestationVariant, conf.Image, region)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fetching image reference: %w", err)
|
||||
}
|
||||
@ -526,5 +530,8 @@ type debugLog interface {
|
||||
|
||||
// imageFetcher gets an image reference from the versionsapi.
|
||||
type imageFetcher interface {
|
||||
FetchReference(ctx context.Context, config *config.Config) (string, error)
|
||||
FetchReference(ctx context.Context,
|
||||
provider cloudprovider.Provider, attestationVariant variant.Variant,
|
||||
image, region string,
|
||||
) (string, error)
|
||||
}
|
||||
|
@ -14,10 +14,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versions/components"
|
||||
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||
@ -550,6 +552,9 @@ type stubImageFetcher struct {
|
||||
fetchReferenceErr error
|
||||
}
|
||||
|
||||
func (f *stubImageFetcher) FetchReference(_ context.Context, _ *config.Config) (string, error) {
|
||||
func (f *stubImageFetcher) FetchReference(_ context.Context,
|
||||
_ cloudprovider.Provider, _ variant.Variant,
|
||||
_, _ string,
|
||||
) (string, error) {
|
||||
return f.reference, f.fetchReferenceErr
|
||||
}
|
||||
|
@ -14,10 +14,10 @@ go_library(
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/constants",
|
||||
"//internal/imagefetcher",
|
||||
"//internal/logger",
|
||||
"//internal/variant",
|
||||
"//internal/versionsapi",
|
||||
"//internal/versionsapi/fetcher",
|
||||
"@sh_helm_helm_v3//pkg/action",
|
||||
"@sh_helm_helm_v3//pkg/cli",
|
||||
],
|
||||
|
@ -10,14 +10,13 @@ package upgrade
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi/fetcher"
|
||||
)
|
||||
|
||||
type upgradeInfo struct {
|
||||
@ -27,13 +26,12 @@ type upgradeInfo struct {
|
||||
}
|
||||
|
||||
func fetchUpgradeInfo(ctx context.Context, csp cloudprovider.Provider,
|
||||
attestationVariant variant.Variant, toImage string,
|
||||
attestationVariant variant.Variant, toImage, region string,
|
||||
) (upgradeInfo, error) {
|
||||
info := upgradeInfo{
|
||||
measurements: make(measurements.M),
|
||||
shortPath: toImage,
|
||||
}
|
||||
versionsClient := fetcher.NewFetcher()
|
||||
|
||||
ver, err := versionsapi.NewVersionFromShortPath(toImage, versionsapi.VersionKindImage)
|
||||
if err != nil {
|
||||
@ -55,11 +53,8 @@ func fetchUpgradeInfo(ctx context.Context, csp cloudprovider.Provider,
|
||||
}
|
||||
info.measurements = fetchedMeasurements
|
||||
|
||||
imageRef, err := fetchImageRef(ctx, versionsClient, csp, versionsapi.ImageInfo{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Version: ver.Version,
|
||||
})
|
||||
fetcher := imagefetcher.New()
|
||||
imageRef, err := fetcher.FetchReference(ctx, csp, attestationVariant, toImage, region)
|
||||
if err != nil {
|
||||
return upgradeInfo{}, err
|
||||
}
|
||||
@ -67,21 +62,3 @@ func fetchUpgradeInfo(ctx context.Context, csp cloudprovider.Provider,
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func fetchImageRef(ctx context.Context, client *fetcher.Fetcher, csp cloudprovider.Provider, imageInfo versionsapi.ImageInfo) (string, error) {
|
||||
imageInfo, err := client.FetchImageInfo(ctx, imageInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch csp {
|
||||
case cloudprovider.GCP:
|
||||
return imageInfo.GCP["sev-es"], nil
|
||||
case cloudprovider.Azure:
|
||||
return imageInfo.Azure["cvm"], nil
|
||||
case cloudprovider.AWS:
|
||||
return imageInfo.AWS["eu-central-1"], nil
|
||||
default:
|
||||
return "", errors.New("finding wanted image")
|
||||
}
|
||||
}
|
||||
|
@ -245,6 +245,7 @@ func writeUpgradeConfig(require *require.Assertions, image string, kubernetes st
|
||||
cfg.GetProvider(),
|
||||
cfg.GetAttestationConfig().GetVariant(),
|
||||
image,
|
||||
cfg.GetRegion(),
|
||||
)
|
||||
require.NoError(err)
|
||||
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
|
||||
type archivist interface {
|
||||
Archive(ctx context.Context,
|
||||
version versionsapi.Version, csp, variant string, img io.Reader,
|
||||
version versionsapi.Version, csp, attestationVariant string, img io.Reader,
|
||||
) (string, error)
|
||||
}
|
||||
|
||||
type uploader interface {
|
||||
Upload(ctx context.Context, req *osimage.UploadRequest) (map[string]string, error)
|
||||
Upload(ctx context.Context, req *osimage.UploadRequest) ([]versionsapi.ImageInfoEntry, error)
|
||||
}
|
||||
|
@ -84,14 +84,14 @@ func runAWS(cmd *cobra.Command, _ []string) error {
|
||||
}
|
||||
|
||||
uploadReq := &osimage.UploadRequest{
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
Variant: flags.variant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
AttestationVariant: flags.attestationVariant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
}
|
||||
return uploadImage(cmd.Context(), archiveC, uploadC, uploadReq, out)
|
||||
}
|
||||
|
@ -85,14 +85,14 @@ func runAzure(cmd *cobra.Command, _ []string) error {
|
||||
}
|
||||
|
||||
uploadReq := &osimage.UploadRequest{
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
Variant: flags.variant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
AttestationVariant: flags.attestationVariant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
}
|
||||
return uploadImage(cmd.Context(), archiveC, uploadC, uploadReq, out)
|
||||
}
|
||||
|
@ -18,16 +18,16 @@ import (
|
||||
)
|
||||
|
||||
type commonFlags struct {
|
||||
rawImage string
|
||||
pki string
|
||||
provider cloudprovider.Provider
|
||||
variant string
|
||||
version versionsapi.Version
|
||||
timestamp time.Time
|
||||
region string
|
||||
bucket string
|
||||
out string
|
||||
logLevel zapcore.Level
|
||||
rawImage string
|
||||
pki string
|
||||
provider cloudprovider.Provider
|
||||
attestationVariant string
|
||||
version versionsapi.Version
|
||||
timestamp time.Time
|
||||
region string
|
||||
bucket string
|
||||
out string
|
||||
logLevel zapcore.Level
|
||||
}
|
||||
|
||||
func parseCommonFlags(cmd *cobra.Command) (commonFlags, error) {
|
||||
@ -43,7 +43,7 @@ func parseCommonFlags(cmd *cobra.Command) (commonFlags, error) {
|
||||
if pki == "" {
|
||||
pki = filepath.Join(workspaceDir, "image/pki")
|
||||
}
|
||||
variant, err := cmd.Flags().GetString("variant")
|
||||
attestationVariant, err := cmd.Flags().GetString("attestation-variant")
|
||||
if err != nil {
|
||||
return commonFlags{}, err
|
||||
}
|
||||
@ -88,15 +88,15 @@ func parseCommonFlags(cmd *cobra.Command) (commonFlags, error) {
|
||||
}
|
||||
|
||||
return commonFlags{
|
||||
rawImage: rawImage,
|
||||
pki: pki,
|
||||
variant: variant,
|
||||
version: ver,
|
||||
timestamp: timestmp,
|
||||
region: region,
|
||||
bucket: bucket,
|
||||
out: out,
|
||||
logLevel: logLevel,
|
||||
rawImage: rawImage,
|
||||
pki: pki,
|
||||
attestationVariant: attestationVariant,
|
||||
version: ver,
|
||||
timestamp: timestmp,
|
||||
region: region,
|
||||
bucket: bucket,
|
||||
out: out,
|
||||
logLevel: logLevel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -85,14 +85,14 @@ func runGCP(cmd *cobra.Command, _ []string) error {
|
||||
}
|
||||
|
||||
uploadReq := &osimage.UploadRequest{
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
Variant: flags.variant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
AttestationVariant: flags.attestationVariant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
}
|
||||
return uploadImage(cmd.Context(), archiveC, uploadC, uploadReq, out)
|
||||
}
|
||||
|
@ -68,14 +68,14 @@ func runNOP(cmd *cobra.Command, provider cloudprovider.Provider, _ []string) err
|
||||
}
|
||||
|
||||
uploadReq := &osimage.UploadRequest{
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
Variant: flags.variant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
Provider: flags.provider,
|
||||
Version: flags.version,
|
||||
AttestationVariant: flags.attestationVariant,
|
||||
SBDatabase: sbDatabase,
|
||||
UEFIVarStore: uefiVarStore,
|
||||
Size: size,
|
||||
Timestamp: flags.timestamp,
|
||||
Image: file,
|
||||
}
|
||||
return uploadImage(cmd.Context(), archiveC, uploadC, uploadReq, out)
|
||||
}
|
||||
|
@ -13,14 +13,13 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
|
||||
)
|
||||
|
||||
func uploadImage(ctx context.Context, archiveC archivist, uploadC uploader, req *osimage.UploadRequest, out io.Writer) error {
|
||||
// upload to S3 archive
|
||||
archiveURL, err := archiveC.Archive(ctx, req.Version, strings.ToLower(req.Provider.String()), req.Variant, req.Image)
|
||||
archiveURL, err := archiveC.Archive(ctx, req.Version, strings.ToLower(req.Provider.String()), req.AttestationVariant, req.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -34,8 +33,12 @@ func uploadImage(ctx context.Context, archiveC archivist, uploadC uploader, req
|
||||
return err
|
||||
}
|
||||
if len(imageReferences) == 0 {
|
||||
imageReferences = map[string]string{
|
||||
req.Variant: archiveURL,
|
||||
imageReferences = []versionsapi.ImageInfoEntry{
|
||||
{
|
||||
CSP: req.Provider.String(),
|
||||
AttestationVariant: req.AttestationVariant,
|
||||
Reference: archiveURL,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,20 +46,7 @@ func uploadImage(ctx context.Context, archiveC archivist, uploadC uploader, req
|
||||
Ref: req.Version.Ref,
|
||||
Stream: req.Version.Stream,
|
||||
Version: req.Version.Version,
|
||||
}
|
||||
switch req.Provider {
|
||||
case cloudprovider.AWS:
|
||||
imageInfo.AWS = imageReferences
|
||||
case cloudprovider.Azure:
|
||||
imageInfo.Azure = imageReferences
|
||||
case cloudprovider.GCP:
|
||||
imageInfo.GCP = imageReferences
|
||||
case cloudprovider.OpenStack:
|
||||
imageInfo.OpenStack = imageReferences
|
||||
case cloudprovider.QEMU:
|
||||
imageInfo.QEMU = imageReferences
|
||||
default:
|
||||
return fmt.Errorf("uploading image: cloud provider %s is not yet supported", req.Provider.String())
|
||||
List: imageReferences,
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(out).Encode(imageInfo); err != nil {
|
||||
|
@ -42,7 +42,7 @@ func newRootCmd() *cobra.Command {
|
||||
|
||||
rootCmd.PersistentFlags().String("raw-image", "", "Path to os image in CSP specific format that should be uploaded.")
|
||||
rootCmd.PersistentFlags().String("pki", "", "Base path to the PKI (secure boot signing) files.")
|
||||
rootCmd.PersistentFlags().String("variant", "", "Variant of the image being uploaded.")
|
||||
rootCmd.PersistentFlags().String("attestation-variant", "", "Attestation variant of the image being uploaded.")
|
||||
rootCmd.PersistentFlags().String("version", "", "Shortname of the os image version.")
|
||||
rootCmd.PersistentFlags().String("timestamp", "", "Optional timestamp to use for resource names. Uses format 2006-01-02T15:04:05Z07:00.")
|
||||
rootCmd.PersistentFlags().String("region", "eu-central-1", "AWS region of the archive S3 bucket")
|
||||
@ -50,7 +50,7 @@ func newRootCmd() *cobra.Command {
|
||||
rootCmd.PersistentFlags().String("out", "", "Optional path to write the upload result to. If not set, the result is written to stdout.")
|
||||
rootCmd.PersistentFlags().Bool("verbose", false, "Enable verbose output")
|
||||
must(rootCmd.MarkPersistentFlagRequired("raw-image"))
|
||||
must(rootCmd.MarkPersistentFlagRequired("variant"))
|
||||
must(rootCmd.MarkPersistentFlagRequired("attestation-variant"))
|
||||
must(rootCmd.MarkPersistentFlagRequired("version"))
|
||||
|
||||
rootCmd.AddCommand(cmd.NewAWSCmd())
|
||||
|
@ -546,6 +546,23 @@ func (c *Config) GetAttestationConfig() AttestationCfg {
|
||||
return &DummyCfg{}
|
||||
}
|
||||
|
||||
// GetRegion returns the configured region.
|
||||
func (c *Config) GetRegion() string {
|
||||
switch c.GetProvider() {
|
||||
case cloudprovider.AWS:
|
||||
return c.Provider.AWS.Region
|
||||
case cloudprovider.Azure:
|
||||
return c.Provider.Azure.Location
|
||||
case cloudprovider.GCP:
|
||||
return c.Provider.GCP.Region
|
||||
case cloudprovider.OpenStack:
|
||||
return c.Provider.OpenStack.RegionName
|
||||
case cloudprovider.QEMU:
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// UpdateMAAURL updates the MAA URL in the config.
|
||||
func (c *Config) UpdateMAAURL(maaURL string) {
|
||||
if c.Attestation.AzureSEVSNP != nil {
|
||||
|
@ -2,16 +2,15 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "image",
|
||||
name = "imagefetcher",
|
||||
srcs = [
|
||||
"image.go",
|
||||
"imagegfetcher.go",
|
||||
"raw.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/image",
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/imagefetcher",
|
||||
visibility = ["//cli:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"//internal/versionsapi",
|
||||
"//internal/versionsapi/fetcher",
|
||||
@ -21,16 +20,16 @@ go_library(
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "image_test",
|
||||
name = "imagefetcher_test",
|
||||
srcs = [
|
||||
"image_test.go",
|
||||
"imagefetcher_test.go",
|
||||
"raw_test.go",
|
||||
],
|
||||
embed = [":image"],
|
||||
embed = [":imagefetcher"],
|
||||
deps = [
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/config",
|
||||
"//internal/file",
|
||||
"//internal/variant",
|
||||
"//internal/versionsapi",
|
||||
"@com_github_spf13_afero//:afero",
|
||||
"@com_github_stretchr_testify//assert",
|
@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
Package image provides helping wrappers around a versionsapi fetcher.
|
||||
Package imagefetcher provides helping wrappers around a versionsapi fetcher.
|
||||
|
||||
It also enables local image overrides and download of raw images.
|
||||
*/
|
||||
package image
|
||||
package imagefetcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -20,7 +20,6 @@ import (
|
||||
"regexp"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi/fetcher"
|
||||
@ -42,14 +41,11 @@ func New() *Fetcher {
|
||||
}
|
||||
|
||||
// FetchReference fetches the image reference for a given image version uid, CSP and image variant.
|
||||
func (f *Fetcher) FetchReference(ctx context.Context, config *config.Config) (string, error) {
|
||||
provider := config.GetProvider()
|
||||
variant, err := imageVariant(provider, config)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("determining variant: %w", err)
|
||||
}
|
||||
|
||||
ver, err := versionsapi.NewVersionFromShortPath(config.Image, versionsapi.VersionKindImage)
|
||||
func (f *Fetcher) FetchReference(ctx context.Context,
|
||||
provider cloudprovider.Provider, attestationVariant variant.Variant,
|
||||
image, region string,
|
||||
) (string, error) {
|
||||
ver, err := versionsapi.NewVersionFromShortPath(image, versionsapi.VersionKindImage)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parsing config image short path: %w", err)
|
||||
}
|
||||
@ -83,29 +79,18 @@ func (f *Fetcher) FetchReference(ctx context.Context, config *config.Config) (st
|
||||
return "", fmt.Errorf("validating image info file: %w", err)
|
||||
}
|
||||
|
||||
return getReferenceFromImageInfo(provider, variant, imgInfo)
|
||||
return getReferenceFromImageInfo(provider, attestationVariant.String(), imgInfo, filters(provider, region)...)
|
||||
}
|
||||
|
||||
// imageVariant returns the image variant for a given CSP and configuration.
|
||||
func imageVariant(provider cloudprovider.Provider, config *config.Config) (string, error) {
|
||||
func filters(provider cloudprovider.Provider, region string) []filter {
|
||||
var filters []filter
|
||||
switch provider {
|
||||
case cloudprovider.AWS:
|
||||
return config.Provider.AWS.Region, nil
|
||||
case cloudprovider.Azure:
|
||||
if config.GetAttestationConfig().GetVariant().Equal(variant.AzureTrustedLaunch{}) {
|
||||
return "trustedlaunch", nil
|
||||
}
|
||||
return "cvm", nil
|
||||
|
||||
case cloudprovider.GCP:
|
||||
return "sev-es", nil
|
||||
case cloudprovider.OpenStack:
|
||||
return "sev", nil
|
||||
case cloudprovider.QEMU:
|
||||
return "default", nil
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported provider: %s", provider)
|
||||
filters = append(filters, func(i versionsapi.ImageInfoEntry) bool {
|
||||
return i.Region == region
|
||||
})
|
||||
}
|
||||
return filters
|
||||
}
|
||||
|
||||
func getFromFile(fs *afero.Afero, imgInfo versionsapi.ImageInfo) (versionsapi.ImageInfo, error) {
|
||||
@ -132,36 +117,36 @@ func imageInfoFilename(imgInfo versionsapi.ImageInfo) string {
|
||||
}
|
||||
|
||||
// getReferenceFromImageInfo returns the image reference for a given CSP and image variant.
|
||||
func getReferenceFromImageInfo(provider cloudprovider.Provider, variant string, imgInfo versionsapi.ImageInfo,
|
||||
func getReferenceFromImageInfo(provider cloudprovider.Provider,
|
||||
attestationVariant string, imgInfo versionsapi.ImageInfo,
|
||||
filt ...filter,
|
||||
) (string, error) {
|
||||
var providerList map[string]string
|
||||
switch provider {
|
||||
case cloudprovider.AWS:
|
||||
providerList = imgInfo.AWS
|
||||
case cloudprovider.Azure:
|
||||
providerList = imgInfo.Azure
|
||||
case cloudprovider.GCP:
|
||||
providerList = imgInfo.GCP
|
||||
case cloudprovider.OpenStack:
|
||||
providerList = imgInfo.OpenStack
|
||||
case cloudprovider.QEMU:
|
||||
providerList = imgInfo.QEMU
|
||||
default:
|
||||
return "", fmt.Errorf("image not available in image info for CSP %q", provider.String())
|
||||
var correctVariant versionsapi.ImageInfoEntry
|
||||
var found bool
|
||||
variantLoop:
|
||||
for _, variant := range imgInfo.List {
|
||||
gotCSP := cloudprovider.FromString(variant.CSP)
|
||||
if gotCSP != provider || variant.AttestationVariant != attestationVariant {
|
||||
continue
|
||||
}
|
||||
for _, f := range filt {
|
||||
if !f(variant) {
|
||||
continue variantLoop
|
||||
}
|
||||
}
|
||||
correctVariant = variant
|
||||
found = true
|
||||
break
|
||||
}
|
||||
if !found {
|
||||
return "", fmt.Errorf("image not available in image info for CSP %q, variant %q and other filters", provider.String(), attestationVariant)
|
||||
}
|
||||
|
||||
if providerList == nil {
|
||||
return "", fmt.Errorf("image not available in image info for CSP %q", provider.String())
|
||||
}
|
||||
|
||||
ref, ok := providerList[variant]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("image not available in image info for variant %q", variant)
|
||||
}
|
||||
|
||||
return ref, nil
|
||||
return correctVariant.Reference, nil
|
||||
}
|
||||
|
||||
type versionsAPIImageInfoFetcher interface {
|
||||
FetchImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) (versionsapi.ImageInfo, error)
|
||||
}
|
||||
|
||||
type filter func(versionsapi.ImageInfoEntry) bool
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package image
|
||||
package imagefetcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -14,8 +14,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -32,49 +32,88 @@ func TestGetReference(t *testing.T) {
|
||||
info versionsapi.ImageInfo
|
||||
provider cloudprovider.Provider
|
||||
variant string
|
||||
filter filter
|
||||
wantReference string
|
||||
wantErr bool
|
||||
}{
|
||||
"reference exists with filter": {
|
||||
info: versionsapi.ImageInfo{
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{CSP: "aws", AttestationVariant: "aws-nitro-tpm", Reference: "someReference"},
|
||||
{CSP: "aws", AttestationVariant: "aws-nitro-tpm", Reference: "someOtherReference", Region: "someRegion"},
|
||||
},
|
||||
},
|
||||
provider: cloudprovider.AWS,
|
||||
variant: "aws-nitro-tpm",
|
||||
filter: func(entry versionsapi.ImageInfoEntry) bool {
|
||||
return entry.Region == "someRegion"
|
||||
},
|
||||
wantReference: "someOtherReference",
|
||||
},
|
||||
"reference exists aws": {
|
||||
info: versionsapi.ImageInfo{AWS: map[string]string{"someVariant": "someReference"}},
|
||||
info: versionsapi.ImageInfo{
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{CSP: "aws", AttestationVariant: "aws-nitro-tpm", Reference: "someReference"},
|
||||
},
|
||||
},
|
||||
provider: cloudprovider.AWS,
|
||||
variant: "someVariant",
|
||||
variant: "aws-nitro-tpm",
|
||||
wantReference: "someReference",
|
||||
},
|
||||
"reference exists azure": {
|
||||
info: versionsapi.ImageInfo{Azure: map[string]string{"someVariant": "someReference"}},
|
||||
info: versionsapi.ImageInfo{
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{CSP: "azure", AttestationVariant: "azure-sev-snp", Reference: "someReference"},
|
||||
},
|
||||
},
|
||||
provider: cloudprovider.Azure,
|
||||
variant: "someVariant",
|
||||
variant: "azure-sev-snp",
|
||||
wantReference: "someReference",
|
||||
},
|
||||
"reference exists gcp": {
|
||||
info: versionsapi.ImageInfo{GCP: map[string]string{"someVariant": "someReference"}},
|
||||
info: versionsapi.ImageInfo{
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{CSP: "gcp", AttestationVariant: "gcp-sev-es", Reference: "someReference"},
|
||||
},
|
||||
},
|
||||
provider: cloudprovider.GCP,
|
||||
variant: "someVariant",
|
||||
variant: "gcp-sev-es",
|
||||
wantReference: "someReference",
|
||||
},
|
||||
"reference exists openstack": {
|
||||
info: versionsapi.ImageInfo{OpenStack: map[string]string{"someVariant": "someReference"}},
|
||||
info: versionsapi.ImageInfo{
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{CSP: "openstack", AttestationVariant: "qemu-vtpm", Reference: "someReference"},
|
||||
},
|
||||
},
|
||||
provider: cloudprovider.OpenStack,
|
||||
variant: "someVariant",
|
||||
variant: "qemu-vtpm",
|
||||
wantReference: "someReference",
|
||||
},
|
||||
"reference exists qemu": {
|
||||
info: versionsapi.ImageInfo{QEMU: map[string]string{"someVariant": "someReference"}},
|
||||
info: versionsapi.ImageInfo{
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{CSP: "qemu", AttestationVariant: "qemu-vtpm", Reference: "someReference"},
|
||||
},
|
||||
},
|
||||
provider: cloudprovider.QEMU,
|
||||
variant: "someVariant",
|
||||
variant: "qemu-vtpm",
|
||||
wantReference: "someReference",
|
||||
},
|
||||
"csp does not exist": {
|
||||
info: versionsapi.ImageInfo{AWS: map[string]string{"someVariant": "someReference"}},
|
||||
info: versionsapi.ImageInfo{List: []versionsapi.ImageInfoEntry{}},
|
||||
provider: cloudprovider.Unknown,
|
||||
variant: "someVariant",
|
||||
wantErr: true,
|
||||
},
|
||||
"variant does not exist": {
|
||||
info: versionsapi.ImageInfo{AWS: map[string]string{"someVariant": "someReference"}},
|
||||
info: versionsapi.ImageInfo{
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{CSP: "aws", AttestationVariant: "dummy", Reference: "someReference"},
|
||||
},
|
||||
},
|
||||
provider: cloudprovider.AWS,
|
||||
variant: "nonExistingVariant",
|
||||
variant: "aws-nitro-tpm",
|
||||
wantErr: true,
|
||||
},
|
||||
"info is empty": {
|
||||
@ -83,12 +122,6 @@ func TestGetReference(t *testing.T) {
|
||||
variant: "someVariant",
|
||||
wantErr: true,
|
||||
},
|
||||
"csp is nil": {
|
||||
info: versionsapi.ImageInfo{AWS: nil},
|
||||
provider: cloudprovider.AWS,
|
||||
variant: "someVariant",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
@ -96,7 +129,11 @@ func TestGetReference(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
reference, err := getReferenceFromImageInfo(tc.provider, tc.variant, tc.info)
|
||||
var filters []filter
|
||||
if tc.filter != nil {
|
||||
filters = []filter{tc.filter}
|
||||
}
|
||||
reference, err := getReferenceFromImageInfo(tc.provider, tc.variant, tc.info, filters...)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
@ -108,79 +145,6 @@ func TestGetReference(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageVariant(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
csp cloudprovider.Provider
|
||||
config *config.Config
|
||||
wantVariant string
|
||||
wantErr bool
|
||||
}{
|
||||
"AWS region": {
|
||||
csp: cloudprovider.AWS,
|
||||
config: &config.Config{Image: "someImage", Provider: config.ProviderConfig{
|
||||
AWS: &config.AWSConfig{Region: "someRegion"},
|
||||
}},
|
||||
wantVariant: "someRegion",
|
||||
},
|
||||
"Azure cvm": {
|
||||
csp: cloudprovider.Azure,
|
||||
config: &config.Config{
|
||||
Image: "someImage", Provider: config.ProviderConfig{Azure: &config.AzureConfig{}},
|
||||
Attestation: config.AttestationConfig{AzureSEVSNP: &config.AzureSEVSNP{}},
|
||||
},
|
||||
wantVariant: "cvm",
|
||||
},
|
||||
"Azure trustedlaunch": {
|
||||
csp: cloudprovider.Azure,
|
||||
config: &config.Config{
|
||||
Image: "someImage", Provider: config.ProviderConfig{Azure: &config.AzureConfig{}},
|
||||
Attestation: config.AttestationConfig{AzureTrustedLaunch: &config.AzureTrustedLaunch{}},
|
||||
},
|
||||
wantVariant: "trustedlaunch",
|
||||
},
|
||||
"GCP": {
|
||||
csp: cloudprovider.GCP,
|
||||
config: &config.Config{Image: "someImage", Provider: config.ProviderConfig{
|
||||
GCP: &config.GCPConfig{},
|
||||
}},
|
||||
wantVariant: "sev-es",
|
||||
},
|
||||
"OpenStack": {
|
||||
csp: cloudprovider.OpenStack,
|
||||
config: &config.Config{Image: "someImage", Provider: config.ProviderConfig{
|
||||
OpenStack: &config.OpenStackConfig{},
|
||||
}},
|
||||
wantVariant: "sev",
|
||||
},
|
||||
"QEMU": {
|
||||
csp: cloudprovider.QEMU,
|
||||
config: &config.Config{Image: "someImage", Provider: config.ProviderConfig{
|
||||
QEMU: &config.QEMUConfig{},
|
||||
}},
|
||||
wantVariant: "default",
|
||||
},
|
||||
"invalid": {
|
||||
csp: cloudprovider.Provider(9999),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
vari, err := imageVariant(tc.csp, tc.config)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantVariant, vari)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchReference(t *testing.T) {
|
||||
img := "ref/abc/stream/nightly/v1.2.3"
|
||||
newImgInfo := func() versionsapi.ImageInfo {
|
||||
@ -188,49 +152,47 @@ func TestFetchReference(t *testing.T) {
|
||||
Ref: "abc",
|
||||
Stream: "nightly",
|
||||
Version: "v1.2.3",
|
||||
QEMU: map[string]string{"default": "someReference"},
|
||||
AWS: map[string]string{"foo": "bar"},
|
||||
Azure: map[string]string{"foo": "bar"},
|
||||
GCP: map[string]string{"foo": "bar"},
|
||||
List: []versionsapi.ImageInfoEntry{
|
||||
{
|
||||
CSP: "qemu",
|
||||
AttestationVariant: "dummy",
|
||||
Reference: "someReference",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
imgInfoPath := imageInfoFilename(newImgInfo())
|
||||
|
||||
testCases := map[string]struct {
|
||||
config *config.Config
|
||||
provider cloudprovider.Provider
|
||||
image string
|
||||
imageInfoFetcher versionsAPIImageInfoFetcher
|
||||
localFile []byte
|
||||
wantReference string
|
||||
wantErr bool
|
||||
}{
|
||||
"reference fetched remotely": {
|
||||
config: &config.Config{
|
||||
Image: img,
|
||||
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||
},
|
||||
provider: cloudprovider.QEMU,
|
||||
image: img,
|
||||
imageInfoFetcher: &stubVersionsAPIImageFetcher{
|
||||
fetchImageInfoInfo: newImgInfo(),
|
||||
},
|
||||
wantReference: "someReference",
|
||||
},
|
||||
"reference fetched remotely fails": {
|
||||
config: &config.Config{
|
||||
Image: img,
|
||||
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||
},
|
||||
provider: cloudprovider.QEMU,
|
||||
image: img,
|
||||
imageInfoFetcher: &stubVersionsAPIImageFetcher{
|
||||
fetchImageInfoErr: errors.New("failed"),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"reference fetched locally": {
|
||||
config: &config.Config{
|
||||
Image: img,
|
||||
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||
},
|
||||
provider: cloudprovider.QEMU,
|
||||
image: img,
|
||||
localFile: func() []byte {
|
||||
info := newImgInfo()
|
||||
info.QEMU["default"] = "localOverrideReference"
|
||||
info.List[0].Reference = "localOverrideReference"
|
||||
file, err := json.Marshal(info)
|
||||
require.NoError(t, err)
|
||||
return file
|
||||
@ -238,16 +200,14 @@ func TestFetchReference(t *testing.T) {
|
||||
wantReference: "localOverrideReference",
|
||||
},
|
||||
"local file first": {
|
||||
config: &config.Config{
|
||||
Image: img,
|
||||
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||
},
|
||||
provider: cloudprovider.QEMU,
|
||||
image: img,
|
||||
imageInfoFetcher: &stubVersionsAPIImageFetcher{
|
||||
fetchImageInfoInfo: newImgInfo(),
|
||||
},
|
||||
localFile: func() []byte {
|
||||
info := newImgInfo()
|
||||
info.QEMU["default"] = "localOverrideReference"
|
||||
info.List[0].Reference = "localOverrideReference"
|
||||
file, err := json.Marshal(info)
|
||||
require.NoError(t, err)
|
||||
return file
|
||||
@ -255,18 +215,14 @@ func TestFetchReference(t *testing.T) {
|
||||
wantReference: "localOverrideReference",
|
||||
},
|
||||
"local file is invalid": {
|
||||
config: &config.Config{
|
||||
Image: img,
|
||||
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||
},
|
||||
provider: cloudprovider.QEMU,
|
||||
image: img,
|
||||
localFile: []byte("invalid"),
|
||||
wantErr: true,
|
||||
},
|
||||
"local file has invalid image info": {
|
||||
config: &config.Config{
|
||||
Image: img,
|
||||
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||
},
|
||||
provider: cloudprovider.QEMU,
|
||||
image: img,
|
||||
localFile: func() []byte {
|
||||
info := newImgInfo()
|
||||
info.Ref = ""
|
||||
@ -277,11 +233,9 @@ func TestFetchReference(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
"image version does not exist": {
|
||||
config: &config.Config{
|
||||
Image: "nonExistingImageName",
|
||||
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||
},
|
||||
wantErr: true,
|
||||
provider: cloudprovider.QEMU,
|
||||
image: "nonExistingImageName",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -302,7 +256,7 @@ func TestFetchReference(t *testing.T) {
|
||||
fs: af,
|
||||
}
|
||||
|
||||
reference, err := fetcher.FetchReference(context.Background(), tc.config)
|
||||
reference, err := fetcher.FetchReference(context.Background(), tc.provider, variant.Dummy{}, tc.image, "someRegion")
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package image
|
||||
package imagefetcher
|
||||
|
||||
import (
|
||||
"context"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package image
|
||||
package imagefetcher
|
||||
|
||||
import (
|
||||
"bytes"
|
@ -51,7 +51,7 @@ func (a *Archivist) Archive(ctx context.Context, version versionsapi.Version, cs
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
a.log.Debugf("Archiving OS image %s %s %v to s3://%v/%v", csp, variant, version.ShortPath(), a.bucket, key)
|
||||
a.log.Debugf("Archiving OS image %s %s %v to s3://%v/%v", csp, attestationVariant, version.ShortPath(), a.bucket, key)
|
||||
_, err = a.uploadClient.Upload(ctx, &s3.PutObjectInput{
|
||||
Bucket: &a.bucket,
|
||||
Key: &key,
|
||||
|
@ -72,7 +72,7 @@ func New(region, bucketName string, log *logger.Logger) (*Uploader, error) {
|
||||
}
|
||||
|
||||
// Upload uploads an OS image to AWS.
|
||||
func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[string]string, error) {
|
||||
func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) ([]versionsapi.ImageInfoEntry, error) {
|
||||
blobName := fmt.Sprintf("image-%s-%s-%d.raw", req.Version.Stream, req.Version.Version, req.Timestamp.Unix())
|
||||
imageName := imageName(req.Version, req.Timestamp)
|
||||
allRegions := []string{u.region}
|
||||
@ -129,6 +129,7 @@ func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[
|
||||
}
|
||||
|
||||
// wait for replication, tag, publish
|
||||
var imageInfo []versionsapi.ImageInfoEntry
|
||||
for _, region := range allRegions {
|
||||
if err := u.waitForImage(ctx, amiIDs[region], region); err != nil {
|
||||
return nil, fmt.Errorf("waiting for image to become available in region %s: %w", region, err)
|
||||
@ -142,8 +143,15 @@ func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[
|
||||
if err := u.publishImage(ctx, amiIDs[region], region); err != nil {
|
||||
return nil, fmt.Errorf("publishing image in region %s: %w", region, err)
|
||||
}
|
||||
imageInfo = append(imageInfo, versionsapi.ImageInfoEntry{
|
||||
CSP: "aws",
|
||||
AttestationVariant: req.AttestationVariant,
|
||||
Reference: amiIDs[region],
|
||||
Region: region,
|
||||
})
|
||||
}
|
||||
return amiIDs, nil
|
||||
|
||||
return imageInfo, nil
|
||||
}
|
||||
|
||||
func (u *Uploader) ensureBucket(ctx context.Context) error {
|
||||
|
@ -93,9 +93,9 @@ func New(subscription, location, resourceGroup string, log *logger.Logger) (*Upl
|
||||
}
|
||||
|
||||
// Upload uploads an OS image to Azure.
|
||||
func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[string]string, error) {
|
||||
func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) ([]versionsapi.ImageInfoEntry, error) {
|
||||
formattedTime := req.Timestamp.Format(timestampFormat)
|
||||
diskName := fmt.Sprintf("constellation-%s-%s-%s", req.Version.Stream, formattedTime, req.Variant)
|
||||
diskName := fmt.Sprintf("constellation-%s-%s-%s", req.Version.Stream, formattedTime, req.AttestationVariant)
|
||||
var sigName string
|
||||
switch req.Version.Stream {
|
||||
case "stable":
|
||||
@ -140,7 +140,7 @@ func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[
|
||||
if err := u.ensureSIG(ctx, sigName); err != nil {
|
||||
return nil, fmt.Errorf("ensuring sig exists: %w", err)
|
||||
}
|
||||
if err := u.ensureImageDefinition(ctx, sigName, definitionName, req.Version, req.Variant); err != nil {
|
||||
if err := u.ensureImageDefinition(ctx, sigName, definitionName, req.Version, req.AttestationVariant); err != nil {
|
||||
return nil, fmt.Errorf("ensuring image definition exists: %w", err)
|
||||
}
|
||||
|
||||
@ -154,8 +154,12 @@ func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[
|
||||
return nil, fmt.Errorf("getting image reference: %w", err)
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
req.Variant: imageReference,
|
||||
return []versionsapi.ImageInfoEntry{
|
||||
{
|
||||
CSP: "azure",
|
||||
AttestationVariant: req.AttestationVariant,
|
||||
Reference: imageReference,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -337,7 +341,7 @@ func (u *Uploader) ensureSIG(ctx context.Context, sigName string) error {
|
||||
}
|
||||
|
||||
// ensureImageDefinition creates an image definition (component of a SIG) if it does not exist yet.
|
||||
func (u *Uploader) ensureImageDefinition(ctx context.Context, sigName, definitionName string, version versionsapi.Version, variant string) error {
|
||||
func (u *Uploader) ensureImageDefinition(ctx context.Context, sigName, definitionName string, version versionsapi.Version, attestationVariant string) error {
|
||||
_, err := u.image.Get(ctx, u.resourceGroup, sigName, definitionName, &armcomputev4.GalleryImagesClientGetOptions{})
|
||||
if err == nil {
|
||||
u.log.Debugf("Image definition %s/%s in %s exists", sigName, definitionName, u.resourceGroup)
|
||||
@ -349,10 +353,10 @@ func (u *Uploader) ensureImageDefinition(ctx context.Context, sigName, definitio
|
||||
// based on wether a VMGS was provided or not.
|
||||
// VMGS provided: ConfidentialVM
|
||||
// No VMGS provided: ConfidentialVMSupported
|
||||
switch strings.ToLower(variant) {
|
||||
case "cvm":
|
||||
switch strings.ToLower(attestationVariant) {
|
||||
case "azure-sev-snp":
|
||||
securityType = string("ConfidentialVMSupported")
|
||||
case "trustedlaunch":
|
||||
case "azure-trustedlaunch":
|
||||
securityType = string(armcomputev4.SecurityTypesTrustedLaunch)
|
||||
}
|
||||
offer := imageOffer(version)
|
||||
|
@ -61,8 +61,8 @@ func New(ctx context.Context, project, location, bucketName string, log *logger.
|
||||
}
|
||||
|
||||
// Upload uploads an OS image to GCP.
|
||||
func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[string]string, error) {
|
||||
imageName := u.imageName(req.Version, req.Variant)
|
||||
func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) ([]versionsapi.ImageInfoEntry, error) {
|
||||
imageName := u.imageName(req.Version, req.AttestationVariant)
|
||||
blobName := imageName + ".tar.gz"
|
||||
if err := u.ensureBucket(ctx); err != nil {
|
||||
return nil, fmt.Errorf("setup: ensuring bucket exists: %w", err)
|
||||
@ -86,8 +86,12 @@ func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating image: %w", err)
|
||||
}
|
||||
return map[string]string{
|
||||
req.Variant: imageRef,
|
||||
return []versionsapi.ImageInfoEntry{
|
||||
{
|
||||
CSP: "gcp",
|
||||
AttestationVariant: req.AttestationVariant,
|
||||
Reference: imageRef,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -220,8 +224,8 @@ func (u *Uploader) blobURL(blobName string) string {
|
||||
}).String()
|
||||
}
|
||||
|
||||
func (u *Uploader) imageName(version versionsapi.Version, variant string) string {
|
||||
return strings.ReplaceAll(version.Version, ".", "-") + "-" + variant + "-" + version.Stream
|
||||
func (u *Uploader) imageName(version versionsapi.Version, attestationVariant string) string {
|
||||
return strings.ReplaceAll(version.Version, ".", "-") + "-" + attestationVariant + "-" + version.Stream
|
||||
}
|
||||
|
||||
func (u *Uploader) imageFamily(version versionsapi.Version) string {
|
||||
|
@ -8,5 +8,6 @@ go_library(
|
||||
deps = [
|
||||
"//internal/logger",
|
||||
"//internal/osimage",
|
||||
"//internal/versionsapi",
|
||||
],
|
||||
)
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
|
||||
)
|
||||
|
||||
// Uploader is a no-op uploader.
|
||||
@ -25,7 +26,7 @@ func New(log *logger.Logger) *Uploader {
|
||||
}
|
||||
|
||||
// Upload pretends to upload images to a csp.
|
||||
func (u *Uploader) Upload(_ context.Context, req *osimage.UploadRequest) (map[string]string, error) {
|
||||
func (u *Uploader) Upload(_ context.Context, req *osimage.UploadRequest) ([]versionsapi.ImageInfoEntry, error) {
|
||||
u.log.Debugf("Skipping image upload of %s since this CSP does not require images to be uploaded in advance.", req.Version.ShortPath())
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -18,12 +18,12 @@ import (
|
||||
|
||||
// UploadRequest is a request to upload an os image.
|
||||
type UploadRequest struct {
|
||||
Provider cloudprovider.Provider
|
||||
Version versionsapi.Version
|
||||
Variant string
|
||||
SBDatabase secureboot.Database
|
||||
UEFIVarStore secureboot.UEFIVarStore
|
||||
Size int64
|
||||
Timestamp time.Time
|
||||
Image io.ReadSeeker
|
||||
Provider cloudprovider.Provider
|
||||
Version versionsapi.Version
|
||||
AttestationVariant string
|
||||
SBDatabase secureboot.Database
|
||||
UEFIVarStore secureboot.UEFIVarStore
|
||||
Size int64
|
||||
Timestamp time.Time
|
||||
Image io.ReadSeeker
|
||||
}
|
||||
|
@ -211,24 +211,23 @@ func deleteImage(ctx context.Context, clients rmImageClients, ver versionsapi.Ve
|
||||
return fmt.Errorf("fetching image info: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Deleting AWS images from %s", imageInfo.JSONPath())
|
||||
for awsRegion, awsImage := range imageInfo.AWS {
|
||||
if err := clients.aws.deleteImage(ctx, awsImage, awsRegion, dryrun, log); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting AWS image %s: %w", awsImage, err))
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Deleting GCP images from %s", imageInfo.JSONPath())
|
||||
for _, gcpImage := range imageInfo.GCP {
|
||||
if err := clients.gcp.deleteImage(ctx, gcpImage, dryrun, log); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting GCP image %s: %w", gcpImage, err))
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Deleting Azure images from %s", imageInfo.JSONPath())
|
||||
for _, azImage := range imageInfo.Azure {
|
||||
if err := clients.az.deleteImage(ctx, azImage, dryrun, log); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting Azure image %s: %w", azImage, err))
|
||||
for _, entry := range imageInfo.List {
|
||||
switch entry.CSP {
|
||||
case "aws":
|
||||
log.Infof("Deleting AWS images from %s", imageInfo.JSONPath())
|
||||
if err := clients.aws.deleteImage(ctx, entry.Reference, entry.Region, dryrun, log); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting AWS image %s: %w", entry.Reference, err))
|
||||
}
|
||||
case "gcp":
|
||||
log.Infof("Deleting GCP images from %s", imageInfo.JSONPath())
|
||||
if err := clients.gcp.deleteImage(ctx, entry.Reference, dryrun, log); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting GCP image %s: %w", entry.Reference, err))
|
||||
}
|
||||
case "azure":
|
||||
log.Infof("Deleting Azure images from %s", imageInfo.JSONPath())
|
||||
if err := clients.az.deleteImage(ctx, entry.Reference, dryrun, log); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting Azure image %s: %w", entry.Reference, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,22 +24,22 @@ type ImageInfo struct {
|
||||
Stream string `json:"stream,omitempty"`
|
||||
// Version is the version of the image.
|
||||
Version string `json:"version,omitempty"`
|
||||
// AWS is a map of AWS regions to AMI IDs.
|
||||
AWS map[string]string `json:"aws,omitempty"`
|
||||
// Azure is a map of image types to Azure image IDs.
|
||||
Azure map[string]string `json:"azure,omitempty"`
|
||||
// GCP is a map of image types to GCP image IDs.
|
||||
GCP map[string]string `json:"gcp,omitempty"`
|
||||
// OpenStack is a map of image types to OpenStack image IDs.
|
||||
OpenStack map[string]string `json:"openstack,omitempty"`
|
||||
// QEMU is a map of image types to QEMU image URLs.
|
||||
QEMU map[string]string `json:"qemu,omitempty"`
|
||||
// List contains the image variants for this version.
|
||||
List []ImageInfoEntry `json:"list,omitempty"`
|
||||
}
|
||||
|
||||
// ImageInfoEntry contains information about a single image variant.
|
||||
type ImageInfoEntry struct {
|
||||
CSP string `json:"csp"`
|
||||
AttestationVariant string `json:"attestationVariant"`
|
||||
Reference string `json:"reference"`
|
||||
Region string `json:"region,omitempty"`
|
||||
}
|
||||
|
||||
// JSONPath returns the S3 JSON path for this object.
|
||||
func (i ImageInfo) JSONPath() string {
|
||||
return path.Join(
|
||||
constants.CDNAPIPrefix,
|
||||
constants.CDNAPIPrefixV2,
|
||||
"ref", i.Ref,
|
||||
"stream", i.Stream,
|
||||
i.Version,
|
||||
@ -71,20 +71,8 @@ func (i ImageInfo) ValidateRequest() error {
|
||||
if !semver.IsValid(i.Version) {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semver", i.Version))
|
||||
}
|
||||
if len(i.AWS) != 0 {
|
||||
retErr = errors.Join(retErr, errors.New("AWS map must be empty for request"))
|
||||
}
|
||||
if len(i.Azure) != 0 {
|
||||
retErr = errors.Join(retErr, errors.New("Azure map must be empty for request"))
|
||||
}
|
||||
if len(i.GCP) != 0 {
|
||||
retErr = errors.Join(retErr, errors.New("GCP map must be empty for request"))
|
||||
}
|
||||
if len(i.OpenStack) != 0 {
|
||||
retErr = errors.Join(retErr, errors.New("OpenStack map must be empty for request"))
|
||||
}
|
||||
if len(i.QEMU) != 0 {
|
||||
retErr = errors.Join(retErr, errors.New("QEMU map must be empty for request"))
|
||||
if len(i.List) != 0 {
|
||||
retErr = errors.Join(retErr, errors.New("list must be empty for request"))
|
||||
}
|
||||
|
||||
return retErr
|
||||
@ -102,14 +90,8 @@ func (i ImageInfo) Validate() error {
|
||||
if !semver.IsValid(i.Version) {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semver", i.Version))
|
||||
}
|
||||
var providers int
|
||||
providers += len(i.AWS)
|
||||
providers += len(i.Azure)
|
||||
providers += len(i.GCP)
|
||||
providers += len(i.OpenStack)
|
||||
providers += len(i.QEMU)
|
||||
if providers == 0 {
|
||||
retErr = errors.Join(retErr, errors.New("one or more providers must be specified"))
|
||||
if len(i.List) == 0 {
|
||||
retErr = errors.Join(retErr, errors.New("one or more image variants must be specified in the list"))
|
||||
}
|
||||
|
||||
return retErr
|
||||
|
@ -24,7 +24,7 @@ func TestImageInfoJSONPath(t *testing.T) {
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
},
|
||||
wantPath: constants.CDNAPIPrefix + "/ref/test-ref/stream/nightly/v1.0.0/image/info.json",
|
||||
wantPath: constants.CDNAPIPrefixV2 + "/ref/test-ref/stream/nightly/v1.0.0/image/info.json",
|
||||
},
|
||||
"image info release": {
|
||||
info: ImageInfo{
|
||||
@ -32,7 +32,7 @@ func TestImageInfoJSONPath(t *testing.T) {
|
||||
Stream: "stable",
|
||||
Version: "v1.0.0",
|
||||
},
|
||||
wantPath: constants.CDNAPIPrefix + "/ref/-/stream/stable/v1.0.0/image/info.json",
|
||||
wantPath: constants.CDNAPIPrefixV2 + "/ref/-/stream/stable/v1.0.0/image/info.json",
|
||||
},
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ func TestImageInfoURL(t *testing.T) {
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
},
|
||||
wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/test-ref/stream/nightly/v1.0.0/image/info.json",
|
||||
wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefixV2 + "/ref/test-ref/stream/nightly/v1.0.0/image/info.json",
|
||||
},
|
||||
"image info release": {
|
||||
info: ImageInfo{
|
||||
@ -63,7 +63,7 @@ func TestImageInfoURL(t *testing.T) {
|
||||
Stream: "stable",
|
||||
Version: "v1.0.0",
|
||||
},
|
||||
wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/-/stream/stable/v1.0.0/image/info.json",
|
||||
wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefixV2 + "/ref/-/stream/stable/v1.0.0/image/info.json",
|
||||
},
|
||||
}
|
||||
|
||||
@ -87,10 +87,35 @@ func TestImageInfoValidate(t *testing.T) {
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
AWS: map[string]string{"key": "value", "key2": "value2"},
|
||||
GCP: map[string]string{"key": "value", "key2": "value2"},
|
||||
Azure: map[string]string{"key": "value", "key2": "value2"},
|
||||
QEMU: map[string]string{"key": "value", "key2": "value2"},
|
||||
List: []ImageInfoEntry{
|
||||
{
|
||||
CSP: "aws",
|
||||
AttestationVariant: "aws-nitro-tpm",
|
||||
Reference: "ami-123",
|
||||
Region: "us-east-1",
|
||||
},
|
||||
{
|
||||
CSP: "aws",
|
||||
AttestationVariant: "aws-nitro-tpm",
|
||||
Reference: "ami-123",
|
||||
Region: "us-east-2",
|
||||
},
|
||||
{
|
||||
CSP: "gcp",
|
||||
AttestationVariant: "gcp-sev-es",
|
||||
Reference: "gcp-123",
|
||||
},
|
||||
{
|
||||
CSP: "azure",
|
||||
AttestationVariant: "azure-sev-snp",
|
||||
Reference: "azure-123",
|
||||
},
|
||||
{
|
||||
CSP: "qemu",
|
||||
AttestationVariant: "qemu-vtpm",
|
||||
Reference: "https://example.com/qemu-123/image.raw",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid ref": {
|
||||
@ -98,10 +123,14 @@ func TestImageInfoValidate(t *testing.T) {
|
||||
Ref: "",
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
AWS: map[string]string{"key": "value", "key2": "value2"},
|
||||
GCP: map[string]string{"key": "value", "key2": "value2"},
|
||||
Azure: map[string]string{"key": "value", "key2": "value2"},
|
||||
QEMU: map[string]string{"key": "value", "key2": "value2"},
|
||||
List: []ImageInfoEntry{
|
||||
{
|
||||
CSP: "aws",
|
||||
AttestationVariant: "aws-nitro-tpm",
|
||||
Reference: "ami-123",
|
||||
Region: "us-east-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
@ -110,10 +139,14 @@ func TestImageInfoValidate(t *testing.T) {
|
||||
Ref: "test-ref",
|
||||
Stream: "",
|
||||
Version: "v1.0.0",
|
||||
AWS: map[string]string{"key": "value", "key2": "value2"},
|
||||
GCP: map[string]string{"key": "value", "key2": "value2"},
|
||||
Azure: map[string]string{"key": "value", "key2": "value2"},
|
||||
QEMU: map[string]string{"key": "value", "key2": "value2"},
|
||||
List: []ImageInfoEntry{
|
||||
{
|
||||
CSP: "aws",
|
||||
AttestationVariant: "aws-nitro-tpm",
|
||||
Reference: "ami-123",
|
||||
Region: "us-east-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
@ -122,14 +155,18 @@ func TestImageInfoValidate(t *testing.T) {
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
Version: "",
|
||||
AWS: map[string]string{"key": "value", "key2": "value2"},
|
||||
GCP: map[string]string{"key": "value", "key2": "value2"},
|
||||
Azure: map[string]string{"key": "value", "key2": "value2"},
|
||||
QEMU: map[string]string{"key": "value", "key2": "value2"},
|
||||
List: []ImageInfoEntry{
|
||||
{
|
||||
CSP: "aws",
|
||||
AttestationVariant: "aws-nitro-tpm",
|
||||
Reference: "ami-123",
|
||||
Region: "us-east-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"no provider": {
|
||||
"no entries in list": {
|
||||
info: ImageInfo{
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
@ -197,48 +234,19 @@ func TestImageInfoValidateRequest(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid gcp": {
|
||||
"request contains entries": {
|
||||
info: ImageInfo{
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
GCP: map[string]string{"key": "value", "key2": "value2"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid azure": {
|
||||
info: ImageInfo{
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
Azure: map[string]string{"key": "value", "key2": "value2"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid aws": {
|
||||
info: ImageInfo{
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
AWS: map[string]string{"key": "value", "key2": "value2"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid qemu": {
|
||||
info: ImageInfo{
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
QEMU: map[string]string{"key": "value", "key2": "value2"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid openstack": {
|
||||
info: ImageInfo{
|
||||
Ref: "test-ref",
|
||||
Stream: "nightly",
|
||||
Version: "v1.0.0",
|
||||
OpenStack: map[string]string{"key": "value", "key2": "value2"},
|
||||
List: []ImageInfoEntry{
|
||||
{
|
||||
CSP: "aws",
|
||||
AttestationVariant: "aws-nitro-tpm",
|
||||
Reference: "ami-123",
|
||||
Region: "us-east-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
@ -247,10 +255,14 @@ func TestImageInfoValidateRequest(t *testing.T) {
|
||||
Ref: "",
|
||||
Stream: "",
|
||||
Version: "",
|
||||
AWS: map[string]string{"key": "value", "key2": "value2"},
|
||||
GCP: map[string]string{"key": "value", "key2": "value2"},
|
||||
Azure: map[string]string{"key": "value", "key2": "value2"},
|
||||
QEMU: map[string]string{"key": "value", "key2": "value2"},
|
||||
List: []ImageInfoEntry{
|
||||
{
|
||||
CSP: "aws",
|
||||
AttestationVariant: "aws-nitro-tpm",
|
||||
Reference: "ami-123",
|
||||
Region: "us-east-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user